mysql的where查询语句后有多个“or”的SQL语句执行分析
看到一篇文章里面提到where查询语句后有多个“or”的SQL语句执行分析,原来没有碰到这样的情况,做个实验测试下,详细过程如下:
一个数据表person有3个字段,都有索引。
mysql> show index from person;
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| person | 0 | PRIMARY | 1 | id | A | 9 | NULL | NULL | | BTREE | |
| person | 1 | name | 1 | name | A | 9 | NULL | NULL | YES | BTREE | |
| person | 1 | descs | 1 | descs | A | 9 | NULL | NULL | YES | BTREE | |
+--------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
3 rows in set (0.00 sec)
一个字段的情况,用到了索引,是正常的。
mysql> explain select * from person where id = 3;
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | person | const | PRIMARY | PRIMARY | 2 | const | 1 | |
+----+-------------+--------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)
mysql> explain select * from person where name = 'chF';
+----+-------------+--------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | person | ref | name | name | 181 | const | 1 | Using where |
+----+-------------+--------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
mysql> explain select * from person where descs = 'tA1C+_2BbU9YMATi';
+----+-------------+--------+------+---------------+-------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+-------+---------+-------+------+-------------+
| 1 | SIMPLE | person | ref | descs | descs | 63 | const | 1 | Using where |
+----+-------------+--------+------+---------------+-------+---------+-------+------+-------------+
1 row in set (0.00 sec)
2个字段的情况,用到了索引,正常。
mysql> explain select * from person where id = 3 or descs = 'tA1C+_2BbU9YMATi';
+----+-------------+--------+-------------+---------------+---------------+---------+------+------+-----------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------------+---------------+---------------+---------+------+------+-----------------------------------------+
| 1 | SIMPLE | person | index_merge | PRIMARY,descs | PRIMARY,descs | 2,63 | NULL | 2 | Using union(PRIMARY,descs); Using where |
+----+-------------+--------+-------------+---------------+---------------+---------+------+------+-----------------------------------------+
1 row in set (0.00 sec)
mysql> explain select * from person where name = 'syy' or descs = 'tA1C+_2BbU9YMATi';
+----+-------------+--------+-------------+---------------+------------+---------+------+------+--------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------------+---------------+------------+---------+------+------+--------------------------------------+
| 1 | SIMPLE | person | index_merge | name,descs | name,descs | 181,63 | NULL | 2 | Using union(name,descs); Using where |
+----+-------------+--------+-------------+---------------+------------+---------+------+------+--------------------------------------+
1 row in set (0.00 sec)
3个字段的情况,没有用到索引,异常。
mysql> explain select * from person where id = 3 or name = 'syy' or descs = 'tA1C+_2BbU9YMATi';
+----+-------------+--------+------+--------------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+--------------------+------+---------+------+------+-------------+
| 1 | SIMPLE | person | ALL | PRIMARY,name,descs | NULL | NULL | NULL | 9 | Using where |
+----+-------------+--------+------+--------------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
强制使用其中2个字段,没有用到索引,异常。
mysql> explain select * from person force index(primary, name) where id = 3 or name = 'syy' or descs = 'tA1C+_2BbU9YMATi';
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | person | ALL | PRIMARY,name | NULL | NULL | NULL | 9 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
综述所上:
只要是两个索引,都可以走index_merge,换成三个就不行了。
即使是强行指定用某两个索引也不行,索引虽然都能够找到,但优化器不使用任何一个。
原因如下:
即使强制使用了两个索引,那么会有剩下一个条件不会走索引,那么对于该条件的过滤还是要通过表查询,这样,对于 mysql来说就相当于要两个索引的index_mereg后再读表,而且仍然要做一次全表扫描,那还不如就作一次表扫描,Mysql最终还是选择一次表扫描,这样是可以理解的。
在Mysql官方文档上,在提示了mysql用某一个索引后,也就相当于告诉了mysql不要用其他的相关的一些索引。估计 Mysql也并没有去实现三个索引的index_merge,实际上想想就算是实现了,通过读三个索引然后做merge再去取表的记录,其消耗可能也并不会太小,对于Mysql的这个选择也无可厚非。
阅读(1073) | 评论(0) | 转发(0) |