qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請(qǐng)?jiān)L問 http://qaseven.github.io/

          MySQL內(nèi)部臨時(shí)表策略

            通過對(duì)MySQL數(shù)據(jù)庫(kù)源碼的跟蹤和調(diào)試,以及參考MySQL官方文檔,對(duì)MySQL內(nèi)部臨時(shí)表使用策略進(jìn)行整理,以便于更加深入的理解。

            使用內(nèi)部臨時(shí)表?xiàng)l件

            MySQL內(nèi)部臨時(shí)表的使用有一定的策略,從源碼中關(guān)于SQL查詢是否需要內(nèi)部臨時(shí)表。可以總結(jié)如下:

            1、DISTINCT查詢,但是簡(jiǎn)單的DISTINCT查詢,比如對(duì)primary key、unique key等DISTINCT查詢時(shí),查詢優(yōu)化器會(huì)將DISTINCT條件優(yōu)化,去除DISTINCT條件,也不會(huì)創(chuàng)建臨時(shí)表;

            2、不是第一個(gè)表的字段使用ORDER BY 或者GROUP BY;

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

            4、用戶需要緩存結(jié)果;

            5、ROLLUP查詢。

            源碼如下所示

            代碼地址:sql_select.cc:854,函數(shù):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 ));

            內(nèi)部臨時(shí)表使用原則

            但是使用了內(nèi)部臨時(shí)表,那么他是怎么存儲(chǔ)的呢?原則是這樣的:

            1、當(dāng)查詢結(jié)果較小的情況下,使用heap存儲(chǔ)引擎進(jìn)行存儲(chǔ)。也就是說在內(nèi)存中存儲(chǔ)查詢結(jié)果。

            2、當(dāng)查詢結(jié)果較大的情況下,使用myisam存儲(chǔ)引擎進(jìn)行存儲(chǔ)。

            3、當(dāng)查詢結(jié)果最初較小,但是不斷增大的情況下,將會(huì)有從heap存儲(chǔ)引擎轉(zhuǎn)化為myisam存儲(chǔ)引擎存儲(chǔ)查詢結(jié)果。

            什么情況算是查詢結(jié)果較小呢?從源碼中if的幾個(gè)參數(shù)可以看出:

            1、有blob字段的情況;

            2、使用唯一限制的情況;

            3、當(dāng)前表定義為大表的情況;

            4、查詢結(jié)果的選項(xiàng)為小結(jié)果集的情況;

            5、查詢結(jié)果的選項(xiàng)為強(qiáng)制使用myisam的情況

            源碼如下所示

            代碼地址:sql_select.cc:10229,函數(shù):create_tmp_table(),位置:sql_select.cc:10557

          /* If result table is small; use a heap */
            /* future: storage engine selection can be made dynamic? */
            if ( blob_count || using_unique_constraint
                || ( thd->variables .big_tables && !( select_options & SELECT_SMALL_RESULT ))
                || ( select_options & TMP_TABLE_FORCE_MYISAM ))
            {
              share->db_plugin = ha_lock_engine(0, myisam_hton);
              table->file = get_new_handler( share, &table ->mem_root,
                                           share->db_type ());
              if (group &&
                    ( param->group_parts > table-> file->max_key_parts () ||
                     param->group_length > table-> file->max_key_length ()))
                using_unique_constraint=1;
            }
            else
            {
              share->db_plugin = ha_lock_engine(0, heap_hton);
              table->file = get_new_handler( share, &table ->mem_root,
                                           share->db_type ());
            }

            代碼地址:sql_select.cc:11224,函數(shù):create_myisam_from_heap(),位置:sql_select.cc:11287

          /*
              copy all old rows from heap table to MyISAM table
              This is the only code that uses record[1] to read/write but this
              is safe as this is a temporary MyISAM table without timestamp/autoincrement
              or partitioning.
            */
            while (! table->file ->rnd_next( new_table.record [1]))
            {
              write_err= new_table .file-> ha_write_row(new_table .record[1]);
              DBUG_EXECUTE_IF("raise_error" , write_err= HA_ERR_FOUND_DUPP_KEY ;);
              if (write_err )
                goto err ;
            }

            官方文檔相關(guān)內(nèi)容

            以上內(nèi)容只是源碼表面的問題,通過查詢MySQL的官方文檔,得到了更為權(quán)威的官方信息。

            臨時(shí)表創(chuàng)建的條件:

            1、如果order by條件和group by的條件不一樣,或者order by或group by的不是join隊(duì)列中的第一個(gè)表的字段。

            2、DISTINCT聯(lián)合order by條件的查詢。

            3、如果使用了SQL_SMALL_RESULT選項(xiàng),MySQL使用memory臨時(shí)表,否則,查詢?cè)兘Y(jié)果需要存儲(chǔ)到磁盤。

            臨時(shí)表不使用內(nèi)存表的原則:

            1、表中有BLOB或TEXT類型。

            2、group by或distinct條件中的字段大于512個(gè)字節(jié)。

            3、如果使用了UNION或UNION ALL,任何查詢列表中的字段大于512個(gè)字節(jié)。

            此外,使用內(nèi)存表最大為tmp_table_size和max_heap_table_size的最小值。如果超過該值,轉(zhuǎn)化為myisam存儲(chǔ)引擎存儲(chǔ)到磁盤。


          posted on 2012-08-10 09:55 順其自然EVO 閱讀(892) 評(píng)論(0)  編輯  收藏 所屬分類: 數(shù)據(jù)庫(kù)

          <2012年8月>
          2930311234
          567891011
          12131415161718
          19202122232425
          2627282930311
          2345678

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 页游| 青神县| 北安市| 仙游县| 册亨县| 鄂伦春自治旗| 荥经县| 西青区| 黑河市| 定南县| 淮阳县| 广水市| 堆龙德庆县| 富川| 伽师县| 建德市| 浙江省| 郑州市| 安溪县| 蛟河市| 卢龙县| 云浮市| 灌南县| 西宁市| 博白县| 崇义县| 循化| 改则县| 呼和浩特市| 西贡区| 襄城县| 巩留县| 舟山市| 拉萨市| 绥棱县| 吉安市| 金乡县| 陆丰市| 鄯善县| 福海县| 台中市|