MySQL中关于OR条件的优化
转载
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条件的优化的更多相关文章
- MySQL中的SQL的常见优化策略
MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 1 避免全表扫描对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索 ...
- mysql中的SQL_CACHE(性能更优化)
mysql中的sql_cache是个容易忽视的地方,要 使用的话,必须先设置query_cache_size, 以及设置query_cache_type ,其中 query_cache_type 这个 ...
- 在MySQL中如何使用覆盖索引优化limit分页查询
背景 今年3月份时候,线上发生一次大事故.公司主要后端服务器发生宕机,所有接口超时.宕机半小时后,又自动恢复正常.但是过了2小时,又再次发生宕机. 通过接口日志,发现MySQL数据库无法响应服务器.在 ...
- MySQL中Index Condition Pushdown(ICP)优化
在MySQL 5.6开始支持的一种根据索引进行查询的优化方式.之前的MySQL数据库版本不支持ICP,当进行索引查询是,首先根据索引来查找记录,然后在根据WHERE条件来过滤记录.在支持ICP后,My ...
- MySql中的有条件插入 insert where
假设现在我们有这样的需求:当数据库中不存在满足条件的记录时,可以插入一条记录,否则程序退出.该怎么实现? 1年以上工作经验的人应该都能立即想到:去检查一下库里有没有记录,没有就插入,有就结束. int ...
- mysql中的if条件语句用法
· IF(expr1,expr2,expr3) 如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2; ...
- Mysql中谓词使用date_format的优化
优化前: SELECT a.* FROM t1 a, (SELECT obj_id,MAX(PRE_DETAIL_INST_ID) PRE_DETAIL_INST_ID FROM t1 WHERE D ...
- MySQL中怎么将LIMIT分页优化?
1.语法: *** limit [offset,] rows 一般是用于select语句中用以从结果集中拿出特定的一部分数据. offset是偏移量,表示我们现在 ...
- MySQL中的索引优化
MySQL中的SQL的常见优化策略 MySQL中的索引优化 MySQL中的索引简介 过多的使用索引将会造成滥用.因此索引也会有它的缺点.虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行 ...
随机推荐
- HTML基础第五讲---控制表格及其表项的对齐方式
转自:https://i.cnblogs.com/posts?categoryid=1121494 缺省情况下,表格在浏览器屏幕上左对齐,你可以使用<TABLE>的ALIGN属性来指定表格 ...
- vue.js的基础与语法
Vue的实例 创建第一个实例: {{}} 被称之为插值表达式.可以用来进行文本插值. <!DOCTYPE html> <html lang="en"> &l ...
- Python 极简教程(六)运算符
运算符,我们日常生活中使用的加减乘除,都是运算符的一种.当然这种一般我们称为算术运算符,用于处理数字运算的. 但是在计算机语言中,还有很多的运算符.用于处理不用的情况. 主要有以下几类: 算术运算符 ...
- Appium_Java_API
1. driver.findElement(MobileBy.AndroidUIAutomator("邀请")).click();2. driver.findElementById ...
- How to Rotate Tomcat catalina.out
If catalina.out becomes 2GB in size, tomcat crashes and fails to start without any error message. To ...
- SQLite基础学习
SQLite是一款轻量级数据库,集成于android中,以下从分享一下自己学习的. 在查阅资料时有一些好的说明就直接用了: 主要的curd语句 以下SQL语句获取5条记录,跳过前面3条记录 selec ...
- Android圆环控件
Android圆环控件 近期在做一个功能.界面效果要求例如以下: 看到这个界面,我首先想到了曾经在做phone模块的时候,我们定制的来电界面InCallTouchUi,界面效果是相似的. 来电控件使用 ...
- crm翻译导航栏
在crm里面怎样翻译导航栏? 过程例如以下: 1 先新建一个解决方式.把网站地图加进去 2: 然后把这个解决方式到出来来,解压文件: 3:编辑第二个文件: watermark/2/text/aHR0c ...
- 常用协议(SPI, UART, I2C)
SPI: SPI是全双工的同步串行接口,数据速率可达几Mbps,在一般应用中有4根信号线:MOSI, MISO, SCK, SS. 根据时钟极性(CPOL)及相位(CPHA)不同可以组合成4种工作模式 ...
- springboot入门(三)-- springboot集成mybatis及mybatis generator工具使用
前言 mybatis是一个半自动化的orm框架,所谓半自动化就是mybaitis只支持数据库查出的数据映射到pojo类上,而实体到数据库的映射需要自己编写sql语句实现,相较于hibernate这种完 ...