您的位置:首页 > 数据库 > MySQL

关于mysql 使用or连接索引失效引起的慢查询优化的初步实践

2016-12-26 17:18 1026 查看
最近在使用mysql开发时候,遇到稍微多数据时候,sql查询中的order by 语法的查询效率明显的降低了好几个数量级,所以进行了一些sql语句调整或者说是简单优化的尝试。仅供大家参考,或者说是为大家提供一个尝试的思路。
(ps:数据库部署在阿里云服务上,mysql版本5.6,下面sql查询的还仅仅是前15条记录/页)
查询的表就是很常见的商户表(t_merchants)和店铺表(t_shops),sql查询目的是:根据查询条件,查询店铺表,再根据店铺表中关联的商户id将所有的商户信息查询出来,其中,也包括未关联店铺(也就是说商户表中店铺数量字段值为0)的商户。一个商户对应多家店铺,sql如下:


SELECT DISTINCT
m.i_id              MERCHANTID,
m.vc_merchants_name MERCHANTNAME,
m.vc_address        DETAILADDR,
m.i_shop_num        SHOPNUM
FROM
t_merchants m,
t_shop s
where
(
m.i_id = s.i_merchants_id
OR  m.i_shop_num=0)
AND m.i_id IS NOT NULL
AND s.i_state != 4
AND m.i_state !=3
ORDER BY
m.vc_create_time DESC limit 1,10


也就是几百条数据,执行查询居然花费了7s左右(当然,也可能是自身的硬件配置太低也有影响哈哈)。使用explain查询执行过程如下图:



可以看到,是两个表都进行了全表扫描。其中商户表的i_state,vc_create_time和店铺表的i_state,i_merchants_id都是索引列。但是从执行计划看到,并没有用到索引,即索引失效了,主要的问题在于where连接后面的or m.i_shop_num=0这个查询条件,引起索引失效。

*若是将连接条件中“OR m.i_shop_num=0”去掉的话,平均查询时间花费也就是30毫秒左右而已,可见mysql的order by消耗大部分查询时间。

++++++++++++++++++

那么如何能让索引生效呢,就想通过子查询来进行尝试:开始仅仅是通过子查询查询商户表的主键i_id,不需要将商户表的其他字段内容查询出来,第二步通过in语法再次查询商户表的具体字段记录。sql如下:

SELECT
m.i_id              MERCHANTID,
m.vc_merchants_name MERCHANTNAME,
m.vc_address        DETAILADDR,
m.i_shop_num        SHOPNUM
FROM
t_merchants m
where m.i_id in
(
SELECT DISTINCT m1.i_id from t_merchants m1,
t_shop s
where  (
m1.i_id = s.i_merchants_id
OR  m1.i_shop_num=0 )
and
m1.i_id IS NOT NULL
AND s.i_state != 4
AND m1.i_state !=3 )
ORDER BY
m.vc_create_time DESC limit 1,15


查询时间花费60ms左右,相比刚开始的6s、7s而言(>-<||||),那就不用解释了。使用explain查询执行过程如下图:



在商户表和店铺表之间,内部嵌套了一个eq_ref类型扫描查询。所以,大部分的性能提升应该跟它有些关系了。从执行计划中看到,使用了eq_ref唯一索引进行查询扫描,所以速度就上来了。

关于eq_ref的介绍,个人感觉这篇文章介绍挺好:

http://www.cnblogs.com/heat-man/p/4945708.html

所以在写sql时候,可以用explain来查看执行效率,也要注意当where条件后面使用or 后面加上不是索引列的字段,会使得查询不走索引,速度会慢下来,至于更内部原因,还要不断深入学习…..
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mysql