10 mysql選錯索引
在mysql表中可以支援多個索引,有的sql不指定使用哪個索引,由mysql自己來決定,但是有時候mysql選錯了索引,導致執行很慢。
例子create table`t10` (
`id`int(11) not null,
`a`int(11) default null,
`b`int(11) default null,primary key(`id`),key`a` (`a`),key`b` (`b`)
) engine=innodb;
往表中插入10w記錄
過程delimiter ;;create procedureidata_t11()begin
declare i int;set i=1;while(i<=100000)doinsert into t10 values(i, i, i);set i=i+1;end while;end;;
delimiter ;
call idata_t11();
分析sql語句
mysql> select * from t where a between 10000 and 20000;
session a
session b
start transaction with consistent snapshot;
delete from t;
call idata_t11()
explain select * from t10 where a between 10000 and 20000;
commit;
session b的查詢語句explain select * from t10 where a between 10000 and 20000;就不會在選擇所有a了,可以通過慢查詢日誌
set long_query_time=0;select * from t where a between 10000 and 20000; /*q1*/
select * from t force index(a) where a between 10000 and 20000;/*q2*/
優化器的邏輯
選擇索引是優化器的工作,而優化器選擇索引的目的,是找到乙個最優的執行方案,並用最小的代價去執行語句。
在資料庫裡面,掃瞄行數是影響執行代價的因素之一,掃瞄的行數越少,意味著訪問磁碟資料的次數越少,消耗的cpu資源越少。
當然,掃瞄行數並不是唯一的判斷標準,優化器還會結合是否使用臨時表、是否排序等因素綜合判斷。
掃瞄行數是怎麼判斷的?
mysql在真正開始語句執行之前,並不能精確地知道滿足這個條件的記錄是多少,只能根據統計資訊來估算記錄數。
這個統計資訊就是索引的」區分度」,顯然,乙個索引上不同的值越多,這個索引的區分度也就越高,而乙個索引上不同的值的個數,稱為」基數」,這個基數越大越好。
mysql取樣統計的方法,取樣統計的時候,innodb缺省會選擇n個資料頁,統計這些頁面上的不同值,得到乙個平均值,然後乘以這個索引的頁面數,就得到了這個索引的基數。
而資料表是會持續更新的,索引統計資訊也不會固定不變,所以,當變更的行數超過1/m的時候,會自動觸發重新做一次索引統計。
在mysql中,有兩種儲存索引統計的方式,可以通過引數innodb_stats_persitent
([email protected]:3306) [test]> show variables like 'innodb_stats_persistent';+-------------------------+-------+
| variable_name | value |
| innodb_stats_persistent | on |
--設定為on,表示統計資訊會持久化到儲存,預設n=20,m=10
--設定為off,表示統計資訊只儲存在記憶體中,預設n=8,m=16
其實索引統計只是乙個輸入,對於乙個具體的語句來說,優化器還要判斷,執行這個語句要掃瞄多少行
統計資訊不準確,使用analyze table t10;
mysql> explain select * from t where (a between 1 and 1000) and (b between 50000 and 100000) order by b limit 1;
索引選擇異常和處理
一種方法是,採用force index(t)強行選擇乙個索引。
第二種方式就是,可以考慮修改語句,引導mysql使用我們期望的索引。
之前優化器選擇使用索引b,因為它認為使用索引b可以避免排序(b本身是索引,已經是有序的,如果選擇索引b的話,不需要在做排序只需要遍歷),所以即使掃瞄行數更多,也判定為代價更小。
現在使用了 order by b,a,要求按照b,a排序,就意味著使用這兩個索引都需要排序,因此掃瞄行數變成了影響決策的主要條件,此時就選擇了a索引。
當然,這種修改並不是通用的優化手段,只是剛好在這個語句有limit 1,如果都有滿足條件的行,要邏輯結果一致才可以這麼修改。
第三種是在有些場景下,我們可以新建乙個更合適的索引,來提供給優化器做選擇,或者刪掉誤用的索引。
10 mysql選錯索引
在mysql表中可以支援多個索引,有的 sql不指定使用哪個索引,由 mysql 自己來決定,但是有時候 mysql 選錯了索引,導致執行很慢。例子create table t10 id int 11 not null a int 11 default null b int 11 default n...
mysql選錯索引的解決
mysql選錯索引的解決 analyze table 表名 1 強制選擇索引 force index eg select from t force index a where a between 10000 and 20000 缺點 這麼寫不優美 如果索引改了名字,這個語句也得改,顯得很麻煩 遷移資...
MYSQL學習筆記之選錯索引
優化器的目的是選擇索引。他會根據自己內部的判斷,從而選擇乙個最優的執行方案。而判斷是乙個因素就是掃瞄行數,越少的掃瞄行數,就說明訪問磁碟的資料次數越少,消耗的cpu資源也就越少。1.掃瞄行數如何判斷 mysql開始執行之前,並不能知道,滿足這個條件的記錄有多少,而只能採用統計的方法,進行預估。這個統...