转载

MySQL在 5.0版本中引入新特性:索引合并优化(Index merge optimization),当查询中单张表可以使用多个索引时,同时扫描多个索引并将扫描结果进行合并。

该特新主要应用于以下三种场景:

1、      对OR语句求并集,如查询SELECT * FROM TB1 WHERE c1="xxx" OR c2=""xxx"时,如果c1和c2列上分别有索引,可以按照c1和c2条件进行查询,再将查询结果合并(union)操作,得到最终结果

2、      对AND语句求交集,如查询SELECT * FROM TB1 WHERE c1="xxx" AND c2=""xxx"时,如果c1和c2列上分别有索引,可以按照c1和c2条件进行查询,再将查询结果取交集(intersect)操作,得到最终结果

3、      对AND和OR组合语句求结果

该新特性可以在一些场景中大幅度提升查询性能,但受限于MySQL糟糕的统计信息,也导致很多场景查询性能极差甚至导致数据库崩溃。

以SELECT * FROM TB1 WHERE c1="xxx" AND c2=""xxx" 为例:

1、      当c1列和c2列选择性较高时,按照c1和c2条件进行查询性能较高且返回数据集较小,再对两个数据量较小的数据集求交集的操作成本也较低,最终整个语句查询高效;

2、      当c1列或c2列选择性较差且统计信息不准时,比如整表数据量2000万,按照c2列条件返回1500万数据,按照c1列返回1000条数据,此时按照c2列条件进行索引扫描+聚集索引查找的操作成本极高(可能是整表扫描的百倍消耗),对1000条数据和1500万数据求交集的成本也极高,最终导致整条SQL需要消耗大量CPU和IO资源且相应时间超长,而如果值使用c1列的索引,查询消耗资源较少且性能较高。

由于上述的问题,绝大多数的运维团队都会选择关闭该特性来避免执行异常,京东商城也出现过类似案例,严重影响业务正常运行。

最近系统中发现SQL执行异常,SQL类似为:

SELECT *

FROM tb_xxxx_xxxx

WHERE yn=0

AND C1=‘123456789’

OR C2=‘123456789’;

表上C1和C2列分别建有索引,但OR条件导致仅扫描任何一个索引都无法得到满足条件的全部数据,需要同时扫描两个索引并对两个临时结果求并集,但由于我们关闭了Index merge特性,导致执行优化器只能对表进行全表扫描并导致执行性能不佳。

该问题的临时解决办法为开启Index merge特性,但存在未知风险,因此我们建议修改SQL,将OR操作修改为UNION操作,使得不开启Index merge特性的情况下语句依然能使用多个索引,优化SQL为:

SELECT *

FROM tb_xxxx_xxxx

WHERE yn=0

AND C1=‘123456789’

UNION ALL

SELECT *

FROM tb_xxxx_xxxx

WHERE yn=0

AND C2=‘123456789’

AND C1<>‘123456789’

PS:

1、在第二个SELECT语句中增加第一个SELECT语句条件的反操作,从而保证两个SELECT 语句中没有重复数据,可以使用UNION ALL来求交集,避免UNION所带来的排序消耗。

2、在编写SQL语句时,需要注意OR条件的书写,

原SQL为:

WHERE yn=0

AND C1=‘123456789’

OR C2=‘123456789’

等价于:

WHERE (yn=0 AND C1=‘123456789’)

OR C2=‘123456789’

而实际需求要求所有返回数据满足yn=0的条件,应正确写为:

WHERE yn=0

AND (C1=‘123456789’

OR C2=‘123456789’)

MySQL中关于OR条件的优化的更多相关文章

  1. MySQL中的SQL的常见优化策略

    MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 1 避免全表扫描对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索 ...

  2. mysql中的SQL_CACHE(性能更优化)

    mysql中的sql_cache是个容易忽视的地方,要 使用的话,必须先设置query_cache_size, 以及设置query_cache_type ,其中 query_cache_type 这个 ...

  3. 在MySQL中如何使用覆盖索引优化limit分页查询

    背景 今年3月份时候,线上发生一次大事故.公司主要后端服务器发生宕机,所有接口超时.宕机半小时后,又自动恢复正常.但是过了2小时,又再次发生宕机. 通过接口日志,发现MySQL数据库无法响应服务器.在 ...

  4. MySQL中Index Condition Pushdown(ICP)优化

    在MySQL 5.6开始支持的一种根据索引进行查询的优化方式.之前的MySQL数据库版本不支持ICP,当进行索引查询是,首先根据索引来查找记录,然后在根据WHERE条件来过滤记录.在支持ICP后,My ...

  5. MySql中的有条件插入 insert where

    假设现在我们有这样的需求:当数据库中不存在满足条件的记录时,可以插入一条记录,否则程序退出.该怎么实现? 1年以上工作经验的人应该都能立即想到:去检查一下库里有没有记录,没有就插入,有就结束. int ...

  6. mysql中的if条件语句用法

    · IF(expr1,expr2,expr3) 如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2;  ...

  7. Mysql中谓词使用date_format的优化

    优化前: SELECT a.* FROM t1 a, (SELECT obj_id,MAX(PRE_DETAIL_INST_ID) PRE_DETAIL_INST_ID FROM t1 WHERE D ...

  8. MySQL中怎么将LIMIT分页优化?

     1.语法:       *** limit [offset,] rows       一般是用于select语句中用以从结果集中拿出特定的一部分数据.       offset是偏移量,表示我们现在 ...

  9. MySQL中的索引优化

    MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 过多的使用索引将会造成滥用.因此索引也会有它的缺点.虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 ...

随机推荐

  1. Eclipse如何从导入SVN上导入项目

    1.右键单击,选择 Import,进入导入项目窗口 2.点击选择从SVN检出项目,点击Next下一步 3.选择创建新的资源库位置,点击Next,如果项目之前已经导入过删除掉了,重新导入的时候,只需勾选 ...

  2. 【CS Round #44 (Div. 2 only) D】Count Squares

    [链接]点击打开链接 [题意] 给你一个0..n和0..m的区域. 你可以选定其中的4个点,然后组成一个正方形. 问你可以圈出多少个正方形. (正方形的边不一定和坐标轴平行) [题解] 首先,考虑只和 ...

  3. linux下pthread_cancel无法取消线程的原因

    一个线程能够调用pthread_cancel终止同一进程中的还有一个线程,可是值得强调的是:同一进程的线程间,pthread_cancel向还有一线程发终止信号.系统并不会立即关闭被取消线程,仅仅有在 ...

  4. 将exe添加到windows服务中

    mongod --dbpath D:\MongoDB\data --logpath=D:\MongoDB\logs\mongodb.log --install http://www.cnblogs.c ...

  5. Linux 命令笔记(1)

    [root@Oracle11_2 ~]# ll total -rw-------. root root May : anaconda-ks.cfg drwxr-xr-x. root root May ...

  6. 如何在vue项目中使用百度编辑器ueditor

    百度编辑器官方并没有提供vue项目使用说明,目前网上也有不少人实现了相关功能,这里就不再重复,只是针对自身项目碰到的情况做个记录,就当是熟悉了一遍富文本编辑器的代码结构. 按照网上的做法,基本可以实现 ...

  7. JVM学习:方法重载的优先级

    重载:方法名一致,参数长度或者类型不一致. 先放总结,下面为例子 参数具有继承.实现关系,优先考虑子类: 在不考虑对基本类型自动装拆箱(auto-boxing,auto-unboxing),以及可变长 ...

  8. 【习题 5-9 UVA - 1596】Bug Hunt

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] map模拟 map<string,int>记录每个数组的大小 map <pair<string, int&g ...

  9. cocos2d-x 3.0 android mk文件 之 自己主动遍历*.cpp文件

    还记得上一篇android mk 文件的写法吗?传送门, 我们须要手动去加入 cpp文件.假设cpp一多,那不是要累死? LOCAL_PATH := $(call my-dir) include $( ...

  10. 【JAVA编码专题】总结 分类: B1_JAVA 2015-02-11 15:11 290人阅读 评论(0) 收藏

    第一部分:编码基础 为什么需要编码:用计算机看得懂的语言(二进制数)表示各种各样的字符. 一.基本概念 ASCII.Unicode.big5.GBK等为字符集,它们只定义了这个字符集内有哪些字符,以及 ...