Chinaunix首页 | 论坛 | 博客
  • 博客访问: 442442
  • 博文数量: 96
  • 博客积分: 1110
  • 博客等级: 准尉
  • 技术积分: 662
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-14 18:47
个人简介

拔地气不挠,参天节何劲。 平生观物心,独对秋篁影。

文章分类

全部博文(96)

文章存档

2017年(2)

2016年(7)

2015年(9)

2014年(3)

2013年(10)

2012年(42)

2011年(23)

分类:

2012-08-24 16:51:31

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) |
给主人留下些什么吧!~~