Mysql索引會失效的幾種情況分析
CREATE TABLE `members` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用戶名',
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密碼',
`qq` int(10) DEFAULT NULL COMMENT '密碼',
`register_ip` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '註冊IP',
`wechat` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `password` (`password`(191)) USING BTREE,
KEY `qq` (`qq`)
) ENGINE=MyISAM AUTO_INCREMENT=286 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
1.explain 查看索引使用
- type列,連接類型。一個好的SQL語句至少要達到range級別。杜絕出現all級別。
- possible_keys:顯示可能應用在這張表中的索引,一個或多個。查詢涉及到的字段上若存在索引,則該索引獎盃列出,但不一定被查詢實際使用。
- key列,使用到的索引名。如果沒有選擇索引,值是NULL。可以採取強制索引方式。
- key_len列,索引長度。
- rows列,掃描行數。該值是個預估值。
- extra列,詳細說明。注意,常見的不太友好的值,如下:Using filesort,Using temporary。
1.1type類型
type | 解釋 |
---|---|
null | – |
system | const的特例,僅返回一條數據的時候。 |
const | 查找主鍵索引,返回的數據至多一條(0或者1條)。 屬於精確查找 |
eq_ref | 查找唯一性索引,返回的數據至多一條。屬於精確查找 |
ref | 查找非唯一性索引,返回匹配某一條件的多條數據。屬於精確查找、數據返回可能是多條 |
range | 查找某個索引的部分索引,一般在where子句中使用 < 、>、in、between等關鍵詞。只檢索給定範圍的行,屬於範圍查找 |
index | 查找所有的索引樹,比ALL要快的多,因爲索引文件要比數據文件小的多。 |
ALL | 不使用任何索引,進行全表掃描,性能最差。 |
從下到上逐漸變好,使用的索引至少要達到range 級別。
2.使用or / !=(<>) / not null / is null
or影響
mysql> explain select * from members where name = '1' or wechat = '1';
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | members | ALL | name,name_password | NULL | NULL | NULL | 2 | Using where |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
!=
mysql> explain select * from members where name != '1';
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | members | ALL | name,name_password | NULL | NULL | NULL | 2 | Using where |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
is null
mysql> explain select * from members where name is not null;
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | members | ALL | name,name_password | NULL | NULL | NULL | 2 | Using where |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
is not null
mysql> explain select * from members where name is not null;
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | members | ALL | name,name_password | NULL | NULL | NULL | 2 | Using where |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
3. 字符串類型,where的時候帶引號
mysql> explain select * from members where name = '1';
+----+-------------+---------+-------+--------------------+------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+--------------------+------+---------+-------+------+-------+
| 1 | SIMPLE | members | const | name,name_password | name | 402 | const | 1 | |
+----+-------------+---------+-------+--------------------+------+---------+-------+------+-------+
1 row in set
mysql> explain select * from members where name = 1;
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | members | ALL | name,name_password | NULL | NULL | NULL | 2 | Using where |
+----+-------------+---------+------+--------------------+------+---------+------+------+-------------+
4. 不建議使用%前綴模糊查詢
例如LIKE“%name”或者LIKE“%name%”,這種查詢會導致索引失效而進行全表掃描。
但是可以使用LIKE “name%”。
mysql> explain select name from members where name like '%1';
+----+-------------+---------+-------+---------------+------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+------+---------+------+------+--------------------------+
| 1 | SIMPLE | members | index | NULL | name | 402 | NULL | 2 | Using where; Using index |
+----+-------------+---------+-------+---------------+------+---------+------+------+--------------------------+
1 row in set
mysql> explain select name from members where name like '1%';
+----+-------------+---------+-------+--------------------+------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+--------------------+------+---------+------+------+--------------------------+
| 1 | SIMPLE | members | index | name,name_password | name | 402 | NULL | 2 | Using where; Using index |
+----+-------------+---------+-------+--------------------+------+---------+------+------+--------------------------+
那如何查詢%name%?答案:使用全文索引。
# 更新全文索引
ALTER TABLE `members` ADD FULLTEXT INDEX `name` (`name`);
mysql> explain select name from members where match(name) against ('1' in boolean mode);
+----+-------------+---------+----------+---------------+------+---------+-----+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+----------+---------------+------+---------+-----+------+-------------+
| 1 | SIMPLE | members | fulltext | name | name | 0 | | 1 | Using where |
+----+-------------+---------+----------+---------------+------+---------+-----+------+-------------+
5.索引列上少計算
不在索引列上做任何操作(計算、函數、(自動or手動)類型轉換),會導致索引失效而轉向全表掃描
其中後面那句varchar引號不能丟也是如此,如果是丟了,則會進行自動類型轉換,就相當於計算。
待續。。。。。