<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      MySQL 18 為什么這些SQL語句邏輯相同,性能卻差異巨大?

      在MySQL中,有很多看上去邏輯相同,但性能差異巨大的SQL語句。對這些語句使用不當的話,就會不經意導致整個數據庫壓力變大。本文選擇了三個這樣的案例。

      案例一:條件字段函數操作

      假設現在維護了一個交易系統,其中交易記錄表tradelog包含交易流水號(tradeid)、交易員id(operator)、交易時間(t_modified)等字段。建表語句如下:

      mysql> CREATE TABLE `tradelog` (
        `id` int(11) NOT NULL,
        `tradeid` varchar(32) DEFAULT NULL,
        `operator` int(11) DEFAULT NULL,
        `t_modified` datetime DEFAULT NULL,
        PRIMARY KEY (`id`),
        KEY `tradeid` (`tradeid`),
        KEY `t_modified` (`t_modified`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
      

      目前的需求是,統計發生在所有年份中7月份的交易記錄總數??赡軙@樣寫SQL語句:

      select count(*) from tradelog where month(t_modified)=7;
      

      但這可能需要執行很久,因為如果對字段做了函數計算,就用不上索引了。為什么呢?

      上面是t_modified索引示意圖。如果SQL語句的條件是where t_modified='2018-7-1',引擎會按照綠色箭頭的路線快速定位到結果。但如果要計算month()函數,傳入7這個數字,并不知道如何在樹中查找。也就是說,對索引字段做函數操作,可能會破壞索引值的有序性,因此優化器就決定放棄走樹搜索功能。

      但優化器并不是要放棄使用這個索引。在該案例中,優化器可以選擇遍歷主鍵索引,也可以選擇遍歷t_modified索引,對比索引大小后會選擇遍歷t_modified索引。

      用explain命令查看執行結果:

      • key=t_modified,表示用上了索引;

      • rows=100335,已知測試數據共10萬行,表示這條語句掃描了整個索引的所有值。

      為了讓優化器能按照預期用上t_modified索引的快速定位能力,需要把SQL語句改為基于字段本身的范圍查詢:

      mysql> select count(*) from tradelog where
          -> (t_modified >= '2016-7-1' and t_modified<'2016-8-1') or
          -> (t_modified >= '2017-7-1' and t_modified<'2017-8-1') or 
          -> (t_modified >= '2018-7-1' and t_modified<'2018-8-1');
      

      還有其他的情況,索引可能也會失效,比如:

      • select * from tradelog where id+1=10000,失效;

      • select * from tradelog where id=10000-1,可以。

      案例二:隱式類型轉換

      有一條SQL語句:

      select * from tradelog where tradeid=110717;
      

      explain結果顯示這條語句需要走全表掃描,這是因為tradeid字段類型是varchar(32),而輸入的參數是整型,所以需要做類型轉換。

      那么,數據類型轉換規則是什么?為什么有數據類型轉換,就需要走全索引掃描?

      來看一個簡單的比較select "10">9

      • 如果規則是將字符串轉成數字,那么結果應該是1;

      • 如果規則是將數字轉成字符串,那么結果應該是0。

      驗證結果:

      所以在MySQL中,字符串和數字做比較的話,規則是將字符串轉成數字。

      這時再看案例給出的語句,能發現對于優化器來說,語句等同于:

      select * from tradelog where CAST(tradid AS signed int) = 110717;
      

      而根據案例一,這條語句會索引失效。

      案例三:隱式字符編碼轉換

      假設系統里還有另外一個表trade_detail用于記錄交易的操作細節。為了便于分析,在表中插入一些數據:

      mysql> CREATE TABLE `trade_detail` (
        `id` int(11) NOT NULL,
        `tradeid` varchar(32) DEFAULT NULL,
        `trade_step` int(11) DEFAULT NULL, /*操作步驟*/
        `step_info` varchar(32) DEFAULT NULL, /*步驟信息*/
        PRIMARY KEY (`id`),
        KEY `tradeid` (`tradeid`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      insert into tradelog values(1, 'aaaaaaaa', 1000, now());
      insert into tradelog values(2, 'aaaaaaab', 1000, now());
      insert into tradelog values(3, 'aaaaaaac', 1000, now());
      
      insert into trade_detail values(1, 'aaaaaaaa', 1, 'add');
      insert into trade_detail values(2, 'aaaaaaaa', 2, 'update');
      insert into trade_detail values(3, 'aaaaaaaa', 3, 'commit');
      insert into trade_detail values(4, 'aaaaaaab', 1, 'add');
      insert into trade_detail values(5, 'aaaaaaab', 2, 'update');
      insert into trade_detail values(6, 'aaaaaaab', 3, 'update again');
      insert into trade_detail values(7, 'aaaaaaab', 4, 'commit');
      insert into trade_detail values(8, 'aaaaaaac', 1, 'add');
      insert into trade_detail values(9, 'aaaaaaac', 2, 'update');
      insert into trade_detail values(10, 'aaaaaaac', 3, 'update again');
      insert into trade_detail values(11, 'aaaaaaac', 4, 'commit');
      

      這時,有一條SQL語句:

      select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2; 
      

      其explain結果:

      第一行說明優化器會在tradelog找到id=2的行,這個步驟用上了主鍵索引;第二行key=null,說明沒有用上tradeid索引,進行了全表掃描。

      在該執行計劃中,是從tradelog表取tradeid字段,再去trade_detail表里查詢匹配字段,因此把tradelog稱為驅動表,把trade_detail稱為被驅動表,把tradeid稱為關聯字段。

      該語句的執行流程:

      • 首先根據id在tradelog表找到L2這一行;

      • 從L2取出tradeid字段的值;

      • 根據tradeid到trade_detail表查找條件匹配的行,這個過程是通過遍歷主鍵索引的方式。

      我們本來是希望在trade_detail表里用索引,但最終并沒有。

      究其原因,通常是因為兩個表的字符集不同,一個是utf8,一個是utf8mb4,所以做表連接查詢時用不上關聯字段的索引。那么為什么字符集不同就用不上索引呢?

      如果把流程的最后一步單獨改成SQL語句,那就是:

      select * from trade_detail where tradeid=$L2.tradeid.value;
      

      其中,$L2.tradeid.value的字符集是utf8mb4。由于utf8mb4是utf8的超集,因此這兩個類型的字符串作比較時,MySQL內部會先把utf8字符串轉換成utf8mb4,再做比較,等同于:

      select * from trade_detail  where CONVERT(traideid USING utf8mb4)=$L2.tradeid.value; 
      

      CONVERT在這里表示字符集轉換。而這條語句就相當于案例一的堆索引字段做函數操作,優化器會放棄走樹搜索。

      此時可以看出,字符集不同只是條件,連接過程要求在被驅動表的索引字段上加函數操作,是直接導致對被驅動表做全表掃描的原因。


      作為對比驗證,換一下驅動表和被驅動表:

      select l.operator from tradelog l , trade_detail d where d.tradeid=l.tradeid and d.id=4;
      

      其explain結果:

      從結果可以看出,當trade_detail變成驅動表,此時用上了被驅動表tradelog里的索引。

      假設驅動表trade_detail里id=4的行記為R4,如果我們類似分析該語句的最后一步,其類似:

      select operator from tradelog  where traideid =$R4.tradeid.value; 
      

      又由于有字符串轉換,進一步的,該語句可以寫為:

      select operator from tradelog  where traideid =CONVERT($R4.tradeid.value USING utf8mb4); 
      

      此時可以發現,函數是加在輸入參數上的,這樣是可以用上被驅動表的tradeid索引的。


      理解了原理,如果想要優化語句:

      select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2;
      

      有兩種做法:

      • 把trade_detail表上的tradeid字段的字符集也改成utf8mb4;

      • 如果不支持修改字符集,可以修改SQL語句為

        select d.* from tradelog l , trade_detail d where d.tradeid=CONVERT(l.tradeid USING utf8) and l.id=2; 
        

      最后總結:三個案例其實都想說明同一件事,就是對索引字段做函數操作,可能會破壞索引值的有序性,因此優化器會放棄走樹搜索。

      posted @ 2025-07-20 18:51  叁沐  閱讀(456)  評論(0)    收藏  舉報
      //雪花飄落效果
      主站蜘蛛池模板: 在线中文一区字幕对白| 久久国产精品福利一区二区三区| 大地资源免费视频观看| 无码人妻丰满熟妇啪啪欧美| 99久久婷婷国产综合精品青草漫画| 亚洲精品美女久久久久9999| 国产在线高清视频无码| 国产精品无码专区av在线播放| 日韩丝袜欧美人妻制服| 中文字幕在线精品人妻| 色狠狠色婷婷丁香五月| 亚洲春色在线视频| 亚洲一区在线成人av| 无码免费大香伊蕉在人线国产| 热99久久这里只有精品| 国产精品涩涩涩视频网站| 激情五月日韩中文字幕| 日韩精品一区二区亚洲专区| 亚洲欧美人成电影在线观看| 东京热人妻无码一区二区av| 国产国产精品人体在线视| 天天躁日日摸久久久精品| 国产一区二区三区不卡视频| a毛片免费在线观看| 国产成人av一区二区三区不卡| 少妇xxxxx性开放| 性色av免费观看| 欧美人与动交视频在线观看| 亚洲AV旡码高清在线观看| 日本高清中文字幕免费一区二区| 亚洲大尺度一区二区av| 国产成人精品日本亚洲| 久久精品波多野结衣| 亚洲欧洲∨国产一区二区三区| 久久99精品久久久久久| 少妇粗大进出白浆嘿嘿视频| 国产精品一码在线播放| 人妻精品中文字幕av| 信阳市| 国产视频一区二区三区四区视频| 国产欧美日韩精品丝袜高跟鞋|