講乙個索引失效應對措施的案例

2021-10-16 21:48:10 字數 3744 閱讀 4080

create

table staffs(

id int

primary

keyauto_increment

, name varchar(24

)not

null

default

''comment

'姓名'

, age int

notnull

default

0comment

'年齡'

, pos varchar(20

)not

null de****t''

comment

'職位'

, add_time timestamp

notnull ****ult current_timestamp

comment

'入職時間'

)charset utf8 comment

'員工記錄表'

;insert

into staffs(name,age,pos,add_time)

values

('z3'

,'22'

,'manager'

,now()

);insert

into staffs(name,age,pos,add_time)

values

('july'

,'23'

,'dev'

,now()

);insert

into staffs(name,age,pos,add_time)

values

('2000'

,'23'

,'dev'

,now()

);alter

table staffs add

index idx_staffs_nameagepos(name,age,pos)

;

仔細看我的sql語句,建立乙個員工表staffs,插入了三行資料,建立了索引idx_staffs_nameagepos(name,age,pos)索引的三個值按順序都用上是效果最好的,如圖

如果索引了多列,要遵循該法則。該法則指的是查詢從索引的最左前列開始並且不跳過索引中的列

如上面的索引idx_staffs_nameagepos(name,age,pos)中:

假設跳過了name直接查詢,那麼是全表掃瞄,這裡不做圖示,這種情況下你的索引完全沒用到。

假設有name開頭,跳過了age,用了pos,即跳過了中間的索引列,那麼索引其實只會用到name而已,如圖:

說明:有沒有用到pos欄位查詢,圖中的ref列都只有乙個const,如果pos有用上,那麼二表的ref列應該有兩個const,說明pos沒用上索引,同時key_len列也能說明這個問題

如圖,left(name,4)='july』是mysql的函式,表示查詢name欄位左邊起4位的值為』july』的結果。

從結果上來說,和上面的select語句查詢結果是一致的,但是因為在索引列上做了操作,導致了索引失效。

前後兩句sql語句中,age欄位因為變成了範圍查詢,所以age欄位不再在索引裡起到檢索的作用,而是起到排序的作用,並且pos欄位完全失效

何以見得?

因為首先,如果只用到name欄位,那麼key_len的值應該為74而非78,下圖是三個字段逐步使用時key_len的值:

那麼現在key_len的值為78而非74,就說明age欄位有在用,索引的作用不只有查詢,還有排序,age的查詢作用變弱,並且直接影響到後面的pos索引查詢失效,那麼age起作用的就是排序。

只訪問索引的查詢,即索引列和查詢列一致,減少使用select *。

即,在這個表中最好使用select name,age,pos。這個要根據實際業務來。

注意:這裡的<> 就是不等於,它是乙個符號,而不是小於和大於兩個符號。

但是右邊可以加%(如』abc%』),這樣索引不會失效。

這裡會有乙個面試題:解決like '%字串%'時索引不被使用的方法?

答案:使用覆蓋索引select 主鍵/索引的任意乙個字段都行/最好是按索引順序來(只是最好),在本案例中,索引欄位為name,age,pos。

可行的情況:

select id where 哪個字段都行 like

'%aa%'

;//主鍵

select age where 哪個字段都行 like

'%aa%'

;//索引單獨第二位第三位也行

select age,pos where 哪個字段都行 like

'%aa%'

;//索引第二位第三位一起也行

select name where 哪個字段都行 like

'%aa%'

;//索引第一位肯定行

不行的情況:

//皆為有不是索引的字段

select

*where 哪個字段都行 like

'%aa%'

;select age,add_time where 哪個字段都行 like

'%aa%'

;

這個問題的起因是這樣的:

mysql的功能比較強大,在本案例的表中,name欄位有乙個值是2000,那麼在mysql中,select * from staffs where name='2000'select * from staffs where name=2000都能查出來資料且結果一樣。

但是mysql底層執行時,name欄位本身是varchar型別,後一句select中2000是int型別,mysql自己會做乙個轉化,用的就是函式,那麼參考第3條,索引就失效了。

雖然查詢結果一樣,但查詢效率變低了。

假設有索引index(a,b,c)

where語句

索引使用情況

where a=3

awhere a=3 and b=5

a,bwhere a=3 and b=5 and c=4

a,b,c

where b=3或者where b=3 and c=4或者where c=4

沒有where a=3 and c=5

awhere a=3 and b>4 and c=5

a,bwhere a=3 and b like 『kk%』 and c=4

a,b,c

where a=3 and b like 『%kk』 and c=4

awhere a=3 and b like 『%kk%』 and c=4

awhere a=3 and b like 『k%kk%』 and c=4

a,b,c

乙個VUE的小案例

商品列表 router link router link to newslist 新聞列表 router link br router view router view div body script 1.定義好元件 const newslistcomponent vue.extend const ...

乙個索引引發的問題

215 上了乙個大表的組合索引,引發了查詢sql的執行計畫混亂,最終cpu充到100 業務系統掛掉,庫也幾乎宕掉。1,為什麼建了索引後,oracle執行計畫會亂掉,而且選擇了乙個最慢的執行計畫?dba答覆 表關聯!關聯表越多,oracle選擇執行計畫出錯的概率變大!如何防止此類事件 上索引之前,先固...

乙個差分計算的案例

今天碰到乙個需求需要做趨勢分析,後來在高人指點下使用移動差分函式進行處理。雖然使用這個函式,但是要計算出來還是比較複雜的。建立測試表 create multiset table sxedrm2.test stddev pop no before journal no after journal de...