在mysql表中可以支援多個索引,有的
sql不指定使用哪個索引,由
mysql
自己來決定,但是有時候
mysql
選錯了索引,導致執行很慢。
例子
create往表中插入10w記錄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;
過程
delimiter ;;分析sql語句create
procedure
idata_t11()
begin
declare i int;
set i=1;
while(i<=
100000
)do
insert
into t10 values
(i, i, i);
set i=i+1;
endwhile
;end
;;delimiter ;
call idata_t11();
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
and20000; /*
q1*/
select
*from t force index(a) where a between
10000
and20000;/*
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
1and
1000) and (b between
50000
and100000) order
by b limit 1;
一種方法是,採用force index(t)
強行選擇乙個索引。
第二種方式就是,可以考慮修改語句,引導mysql使用我們期望的索引
。之前優化器選擇使用索引b,因為它認為使用索引
b可以避免排序(
b本身是索引,已經是有序的,如果選擇索引
b的話,不需要在做排序只需要遍歷),所以即使掃瞄行數更多,也判定為代價更小。
現在使用了 order by b,a,要求按照
b,a排序,就意味著使用這兩個索引都需要排序,因此掃瞄行數變成了影響決策的主要條件,此時就選擇了
a索引。
當然,這種修改並不是通用的優化手段,只是剛好在這個語句有limit 1,如果都有滿足條件的行,要邏輯結果一致才可以這麼修改。
第三種是在有些場景下,我們可以新建乙個更合適的索引,來提供給優化器做選擇,或者刪掉誤用的索引
。
mysql索引選錯 10 mysql選錯索引
10 mysql選錯索引 在mysql表中可以支援多個索引,有的sql不指定使用哪個索引,由mysql自己來決定,但是有時候mysql選錯了索引,導致執行很慢。例子create table t10 id int 11 not null,a int 11 default null,b int 11 d...
10 MySQL入門小結
1.連線操作和集合操作 續 由於mysql不支援full join,我麼可以這樣實現 select from a left join b on a.id b.id union select from a right join b on a.id b.id a.先查出左聯接 b.查出右聯接 c.用un...
10 mysql其它常用
1 檢視 開發中不常用 給某個常用的查詢語句設定別名,方便使用 建立 create view 檢視名稱 as sql 修改 alter view 檢視名稱 as sql 刪除 drop view 檢視名稱 檢視是虛擬的而非物理表。2 觸發器 開發中不常用 執行增刪改語句,自動執行設定的關聯語句 觸發...