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

最近在使用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 后面加上不是索引列的字段,会使得查询不走索引,速度会慢下来,至于更内部原因,还要不断深入学习…..

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值