這兩天看到了兩種可能會導(dǎo)致全表掃描的sql,這里給大家看一下,希望可以避免踩坑:
情況1:
強制類型轉(zhuǎn)換的情況下,不會使用索引,會走全表掃描。
舉例如下:
首先我們創(chuàng)建一個表
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`score` varchar(20) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `idx_score` (`score`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8
我們可以看到,這個表有三個字段,其中兩個int類型,一個varchar類型。varchar類型的字段score是一個索引,而id是主鍵。
然后我們給這個表里面插入一些數(shù)據(jù),插入數(shù)據(jù)之后的表如下:
mysql:yeyztest 21:43:12>>select * from test;
+----+------+-------+
| id | age | score |
+----+------+-------+
| 1 | 1 | 5 |
| 2 | 2 | 10 |
| 5 | 5 | 25 |
| 8 | 8 | 40 |
| 9 | 2 | 45 |
| 10 | 5 | 50 |
| 11 | 8 | 55 |
+----+------+-------+
7 rows in set (0.00 sec)
這個時候,我們使用explain語句來查看兩條sql的執(zhí)行情況,分別是:
explain select * from test where score ='10';
explain select * from test where score =10;
結(jié)果如下:
mysql:yeyztest 21:42:29>>explain select * from test where score ='10';
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test | NULL | ref | idx_score | idx_score | 62 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+-----------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql:yeyztest 21:43:06>>explain select * from test where score =10;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | test | NULL | ALL | idx_score | NULL | NULL | NULL | 7 | 14.29 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 3 warnings (0.00 sec)
可以看到,如果我們使用的是varchar類型的值,那么結(jié)果中掃描的行數(shù)rows就是1,而當我們使用的是整數(shù)值10的時候,掃描行數(shù)變?yōu)榱?,證明,如果出現(xiàn)了強制類型轉(zhuǎn)換,則會導(dǎo)致索引失效。
情況2:
反向查詢不能使用索引,會導(dǎo)致全表掃描。
創(chuàng)建一個表test1,它的主鍵是score,然后插入6條數(shù)據(jù):
CREATE TABLE `test1` (
`score` varchar(20) not null default '' ,
PRIMARY KEY (`score`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
mysql:yeyztest 22:09:37>>select * from test1;
+-------+
| score |
+-------+
| 111 |
| 222 |
| 333 |
| 444 |
| 555 |
| 666 |
+-------+
6 rows in set (0.00 sec)
當我們使用反向查找的時候,不會使用到索引,來看下面兩條sql:
explain select * from test1 where score='111';
explain select * from test1 where score!='111';
mysql:yeyztest 22:13:01>>explain select * from test1 where score='111';
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
| 1 | SIMPLE | test1 | NULL | const | PRIMARY | PRIMARY | 62 | const | 1 | 100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql:yeyztest 22:13:08>>explain select * from test1 where score!='111';
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | test1 | NULL | index | PRIMARY | PRIMARY | 62 | NULL | 6 | 100.00 | Using where; Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)
可以看到,使用!=作為條件的時候,掃描的行數(shù)是表的總記錄行數(shù)。因此如果想要使用索引,我們就不能使用反向匹配規(guī)則。
情況3:
某些or值條件可能導(dǎo)致全表掃描。
首先我們創(chuàng)建一個表,并插入幾條數(shù)據(jù):
CREATE TABLE `test4` (
`id` int(11) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
KEY `idx_id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql--dba_admin@127.0.0.1:yeyztest 22:23:44>>select * from test4;
+------+------+
| id | name |
+------+------+
| 1 | aaa |
| 2 | bbb |
| 3 | ccc |
| 4 | yeyz |
| NULL | yeyz |
+------+------+
5 rows in set (0.00 sec)
其中表test4包含兩個字段,id字段是一個索引,而name字段是varchar類型,我們來看下面三個語句的掃描行數(shù):
explain select * from test4 where id=1;
explain select * from test4 where id is null;
explain select * from test4 where id=1 or id is null;
mysql:yeyztest 22:24:12>>explain select * from test4 where id is null;
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+
| 1 | SIMPLE | test4 | NULL | ref | idx_id | idx_id | 5 | const | 1 | 100.00 | Using index condition |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
mysql:yeyztest 22:24:17>>explain select * from test4 where id=1;
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
| 1 | SIMPLE | test4 | NULL | ref | idx_id | idx_id | 5 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+--------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)
mysql:yeyztest 22:24:28>>explain select * from test4 where id=1 or id is null;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | test4 | NULL | ALL | idx_id | NULL | NULL | NULL | 5 | 40.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
可以看到單獨使用id=1和id is null,都只會掃描一行記錄,而使用or將二者連接起來就會導(dǎo)致掃描全表而不使用索引。
簡單總結(jié)一下:
1.強制類型轉(zhuǎn)換的情況下,不會使用索引,會走全表掃描
2.反向查詢不能使用索引,會導(dǎo)致全表掃描。
3.某些or值條件可能導(dǎo)致全表掃描。
以上就是導(dǎo)致MySQL做全表掃描的幾種情況的詳細內(nèi)容,更多關(guān)于MySQL 全表掃描的資料請關(guān)注腳本之家其它相關(guān)文章!
您可能感興趣的文章:- 大幅提升MySQL中InnoDB的全表掃描速度的方法
- MySQL查詢優(yōu)化:LIMIT 1避免全表掃描提高查詢效率
- Mysql如何避免全表掃描的方法