并不是索引越多越好徽龟,索引是一種以空間換取時間的方式檐盟,所以建立索引是要消耗一定的空間却紧,況且在索引的維護上也會消耗資源。本文首發(fā)我的個人博客mysql索引不生效
這里有張用戶瀏覽商品表轴合,建表語句:
CREATE TABLE `product_view` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`product_id` int(11) NOT NULL,
`server_id` int(11) NOT NULL,
`duration` int(11) NOT NULL,
`times` varchar(11) NOT NULL,
`time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `time` (`time`),
KEY `user_product` (`user_id`,`product_id`) USING BTREE,
KEY `times` (`times`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
可以看出目前這張表是有3個索引的:
[圖片上傳失敗...(image-ea2eb4-1662602346130)]
我往這張表里面導入了10萬多條記錄。
[圖片上傳失敗...(image-a4e9e8-1662602346130)]
mysql不走索引的情況
1碗短、like查詢以“%”開頭(如果開頭受葛、結果都有“%”,也不會使用索引,走的是全表掃描)总滩;
[圖片上傳失敗...(image-72d250-1662602346130)]
我這里用了列出了4種情況纲堵,發(fā)現(xiàn)都是全表掃描,不走索引的咳秉⊥裰В可能因為times取值不夠離散,索引沒有走索引澜建。
2向挖、or語句前后沒有同時使用索引;
首先看看or語句前后同時使用索引:
[圖片上傳失敗...(image-4a756f-1662602346130)]
查詢走索引了。
再看看or語句前后沒有同時使用索引炕舵,product_id是索引字段何之,server_id不是索引字段:
[圖片上傳失敗...(image-829359-1662602346130)]
是沒有走索引的。
3咽筋、組合索引中不是使用第一列索引溶推;(不符合最左匹配原則)
這張表索引為時間time和一個組合索引:
[圖片上傳失敗...(image-8b2bf8-1662602346130)]
這里組合索引user_product,我們先使用user_id這個第一列索引奸攻,作為查詢條件蒜危,查看執(zhí)行計劃:
[圖片上傳失敗...(image-dc97c9-1662602346130)]
使用了索引。
接下來使用組合索引user_product的非第一列索引product_id睹耐,再看看執(zhí)行計劃:
[圖片上傳失敗...(image-2d27d4-1662602346130)]
沒有使用索引辐赞。
4、where條件中類型為字符串的字段沒有使用引號引起來硝训;【查詢where條件數(shù)據(jù)類型不匹配也無法使用索引响委,字符串與數(shù)字比較不使用索引,因為正則表達式不使用索引窖梁,如varchar不加單引號的話可能會自動轉換為int型赘风,使索引無效,產生全表掃描】
首先看看where后條件字符串正常使用引號:
[圖片上傳失敗...(image-b1d31e-1662602346130)]
使用了索引纵刘。
where后條件字符串不使用引號邀窃,而使用數(shù)字:
[圖片上傳失敗...(image-836b9a-1662602346130)]
可以看到,查詢沒有走索引假哎。
5蛔翅、當全表掃描速度比索引速度快時,mysql會使用全表掃描位谋,此時索引失效山析;(*數(shù)據(jù)量少*)
我把表數(shù)據(jù)刪了,里面留了7條數(shù)據(jù):
[圖片上傳失敗...(image-95723b-1662602346130)]
條件查詢索引字段列times:
[圖片上傳失敗...(image-e22bc3-1662602346130)]
顯然是沒有走索引的掏父。
6笋轨、在索引字段上使用“not”,“<>”,“!=”等等爵政;
經過驗證發(fā)現(xiàn)仅讽,使用這些符號后,依然會走索引钾挟。
7洁灵、對索引字段進行計算操作、使用函數(shù);
MySql 如果表中某個時間字段(datetime/…)設置了索引掺出,以函數(shù) DATE_FORMAT() 為查詢條件時徽千,為datetime設置的索引不生效,會引起全表掃描導致查詢很慢汤锨。
沒有用函數(shù)時候是走了索引的双抽,查出具體到時分秒的數(shù)據(jù):
[圖片上傳失敗...(image-3d93f8-1662602346130)]
使用函數(shù)data_format函數(shù),查出2020-08-14這一天的所有數(shù)據(jù):
[圖片上傳失敗...(image-dddbd2-1662602346130)]
沒有走索引闲礼,那么怎么解決呢牍汹?
[圖片上傳失敗...(image-46227d-1662602346130)]
如果一定要用函數(shù),比如date_format柬泽,可以通過這種方式慎菲,就會走索引。
8锨并、索引散列值(重復多)不適合建索引露该,例:性別、狀態(tài)等字段不適合琳疏。
不應該建立索引的字段規(guī)則
不應該在字段比較長的字段上建立索引有决,因為會消耗大量的空間
對于頻繁更新闸拿、插入的字段應該少建立索引空盼,因為在修改和插入之后,數(shù)據(jù)庫會去維護索引新荤,會消耗資源
盡量少在無用字段上建立索引【where條件中用不到的字段】
表記錄太少不應該創(chuàng)建索引
數(shù)據(jù)重復且分布平均的表字段不應該創(chuàng)建索引【選擇性太低揽趾,例如性別、狀態(tài)苛骨、真假值等字段】
參與列計算的列不適合建索引【保持列"干凈"篱瞎,比如from_unixtime(create_time) = '2014-05-29'就不能使用到索引,原因是b+樹中存的都是數(shù)據(jù)表中的字段值痒芝,但進行檢索時需要把所有元素都應用函數(shù)才能比較俐筋,顯然成本太大,所以語句應該寫成create_time = unix_timestamp('2014-05-29')】