盡量全值匹配
建表語句:
CREATE TABLE `t_logs` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`action` varchar(100) DEFAULT NULL,
`data` varchar(2000) DEFAULT NULL,
`author_id` int(10) DEFAULT NULL,
`ip` varchar(20) DEFAULT NULL,
`created` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `actionipcreated` (`action`,`created`,`ip`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=938 DEFAULT CHARSET=utf8;
其中有三個(gè)字段是聯(lián)合索引火鼻,在查詢的時(shí)候盡量把where條件跟索引全量匹配室囊,例如:
EXPLAIN select * from t_logs where action = '訪客訪問' and created = '1528366547' and ip = '58.135.82.57';
執(zhí)行計(jì)劃:
+----+-------------+--------+------------+------+-----------------+-----------------+---------+-------------------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+-----------------+-----------------+---------+-------------------+------+----------+-------+
| 1 | SIMPLE | t_logs | NULL | ref | actionipcreated | actionipcreated | 371 | const,const,const | 1 | 100.00 | NULL |
+----+-------------+--------+------------+------+-----------------+-----------------+---------+-------------------+------+----------+-------+
如果條件不允許使用索引列的全局匹配,那么最好使用覆蓋索引魁索,比如:
EXPLAIN select action,created,ip from t_logs where action = '訪客訪問';
執(zhí)行計(jì)劃:
+----+-------------+--------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | t_logs | NULL | ref | actionipcreated | actionipcreated | 303 | const | 195 | 100.00 | Using index |
+----+-------------+--------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------------+
最佳左前綴法則
如果索引了多列融撞,要遵守最左前綴法則。指的是查詢從索引的最左前列開始并且不跳過索引中的列粗蔚。
建表語句:
CREATE TABLE `t_logs` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`action` varchar(100) DEFAULT NULL,
`data` varchar(2000) DEFAULT NULL,
`author_id` int(10) DEFAULT NULL,
`ip` varchar(20) DEFAULT NULL,
`created` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `actionipcreated` (`action`,`created`,`ip`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=938 DEFAULT CHARSET=utf8;
可見尝偎,一個(gè)復(fù)合索引,順序是action,created致扯,ip肤寝,當(dāng)在使用這三個(gè)索引作為條件查詢的時(shí)候可以打亂順序,但不能跳過抖僵。
舉例:
正確的利用了索引的查詢語句:
EXPLAIN select * from t_logs where action = '訪客訪問' and created = '1528366547' and ip = '58.135.82.57';
未全部利用索引進(jìn)行的查詢:
EXPLAIN select * from t_logs where action = '訪客訪問' and ip = '58.135.82.57';
上面的sql語句僅有action列上的索引起作用了鲤看,ip列上的索引是沒有作用的,因?yàn)橹虚g的created列沒有作為查詢條件耍群。
如果既想改變順序义桂,又能利用索引,那還是使用覆蓋索引的方法蹈垢。最佳左前綴法則就是:帶頭大哥不能死澡刹、中間兄弟不能斷。
補(bǔ)充:例如有一個(gè)聯(lián)合索引 idx_nameAgeGender
假如在查詢的時(shí)候三個(gè)字段打亂順序耘婚,是可以用到索引的,因?yàn)閙ysql有自己的優(yōu)化器陆赋。
不在索引列上做任何操作
不在索引列上做任何操作(計(jì)算沐祷、函數(shù)、(自動(dòng)or手動(dòng))類型轉(zhuǎn)換)攒岛,會(huì)導(dǎo)致索引失效而轉(zhuǎn)向全表掃描赖临。
舉例,其中data列是索引列:
EXPLAIN select * from t_logs where left(DATA,4) = 'bcwn'灾锯;
執(zhí)行計(jì)劃:
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | t_logs | NULL | ALL | NULL | NULL | NULL | NULL | 197 | 100.00 | Using where |
+----+-------------+--------+------------+------+---------------+------+---------+------+------+----------+-------------+
范圍條件放最后
存儲(chǔ)引擎不能使用索引中范圍條件右邊的列兢榨。會(huì)導(dǎo)致最后的索引失效。
例子:
EXPLAIN select * from t_logs where action = '訪客訪問' and created < '1528366547' and ip = '58.135.82.57';
導(dǎo)致了ip這列的索引失效了顺饮。
覆蓋索引盡量用
盡量使用覆蓋索引(只訪問索引的查詢(索引列和查詢列一致))吵聪,減少select *的出現(xiàn)。
不等于要甚用
mysql 在使用不等于(!= 或者<>)的時(shí)候無法使用索引會(huì)導(dǎo)致全表掃描兼雄。解決辦法就是使用覆蓋索引吟逝。例子就不舉了,很簡(jiǎn)單赦肋。
Null/Not Null有影響
建表語句:
CREATE TABLE `t_logs` (
`id` int(10) NOT NULL AUTO_INCREMENT,
`action` varchar(100) DEFAULT NULL,
`data` varchar(100) DEFAULT NULL,
`author_id` int(10) DEFAULT NULL,
`ip` varchar(20) DEFAULT NULL,
`created` int(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `actionipcreated` (`action`,`created`,`ip`) USING BTREE,
KEY `data` (`data`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=938 DEFAULT CHARSET=utf8;
這個(gè)情況有點(diǎn)多块攒,具體取決于該字段是否默認(rèn)為NULL,可以去試試佃乘,遇到這種SQL需要根據(jù)實(shí)際情況去優(yōu)化囱井,索引并不一定會(huì)失效。如果說碰到
IS NULL
或IS NOT NULL
一定會(huì)導(dǎo)致索引失效肯定是錯(cuò)了趣避。
Like查詢
like以通配符開頭('%abc...')mysql索引失效會(huì)變成全表掃描的操作庞呕,但不以'%'開頭不會(huì)導(dǎo)致索引失效。
字符類型加引號(hào)
假如一個(gè)列是char或者varchar類型程帕,那么當(dāng)它作為條件的時(shí)候必須加上單引號(hào)千扶,否則會(huì)導(dǎo)致這一列的索引失效料祠。就不舉例子了,也很簡(jiǎn)單澎羞。