通过对MySQL数据库源码的跟踪和调试,以及参考MySQL官方文档,对MySQL内部临时表使用策略进行整理,以便于更加深入的理解。

  使用内部临时表条件

  MySQL内部临时表的使用有一定的策略,从源码中关于SQL查询是否需要内部临时表。可以总结如下:

  1、DISTINCT查询,但是简单的DISTINCT查询,比如对primary key、unique key等DISTINCT查询时,查询优化器会将DISTINCT条件优化,去除DISTINCT条件,也不会创建临时表;

  2、不是第一个表的字段使用ORDER BY 或者GROUP BY;

  3、ORDER BY和GROUP BY使用不同的顺序;

  4、用户需要缓存结果;

  5、ROLLUP查询。

  源码如下所示

  代码地址:sql_select.cc:854,函数:JOIN::optimize(),位置:sql_select.cc:1399


/*
    Check if we need to create a temporary table.
    This has to be done if all tables are not already read (const tables)
    and one of the following conditions holds:
    - We are using DISTINCT (simple distinct's are already optimized away)
    - We are using an ORDER BY or GROUP BY on fields not in the first table
    - We are using different ORDER BY and GROUP BY orders
    - The user wants us to buffer the result.
    When the WITH ROLLUP modifier is present, we cannot skip temporary table
    creation for the DISTINCT clause just because there are only const tables.
  */
  need_tmp= (( const_tables != tables &&
               (( select_distinct || !simple_order || !simple_group) ||
                ( group_list && order ) ||
                test(select_options & OPTION_BUFFER_RESULT))) ||
             ( rollup.state != ROLLUP:: STATE_NONE && select_distinct ));


  内部临时表使用原则

  但是使用了内部临时表,那么他是怎么存储的呢?原则是这样的:

  1、当查询结果较小的情况下,使用heap存储引擎进行存储。也是说在内存中存储查询结果。

  2、当查询结果较大的情况下,使用myisam存储引擎进行存储。

  3、当查询结果初较小,但是不断增大的情况下,将会有从heap存储引擎转化为myisam存储引擎存储查询结果。

  什么情况算是查询结果较小呢?从源码中if的几个参数可以看出:

  1、有blob字段的情况;

  2、使用限制的情况;

  3、当前表定义为大表的情况;

  4、查询结果的选项为小结果集的情况;

  5、查询结果的选项为强制使用myisam的情况。

  源码如下所示

  代码地址:sql_select.cc:10229,函数:create_tmp_table(),位置:sql_select.cc:10557