MySQL性能优化(六)优化or条件

俊达2年前技术文章993

优化器是数据库中非常核心,又非常复杂的一个组件。有的SQL,优化器选择的执行计划并不是最优的,通过改写SQL,可以帮助优化器找到最优的执行计划。

where条件中的or子句,是比较容易出问题的一个场景。

一个例子

SELECT count(1)
FROM car
WHERE is_deleted = 0 AND car_id NOT IN (  
    SELECT car_id FROM product WHERE product_type = 2 AND source = 2)
AND (seller_id = 100 
     OR (creator = 200 AND seller_id = -1))


执行计划

6-1.jpg


上面的SQL中,过滤性好的2个条件seller_id=100和creator = 200使用OR,

分别使用seller_id=100和creator=200过滤数据,再把数据和并起来,比单走seller_id的索引效果好。

mysql支持index_merge的执行计划。但是上面这个例子只用到了seller_id的索引。而seller_id=-1的过滤性差,从执行计划中也可以看到,car表的rows是16万,比较高。


这种情况下,默认的执行计划不够好,我们可以对SQL做一个小小的改造,改成这种形式:

 SELECT sum(a) FROM (
    SELECT count(1) as a FROM car WHERE is_deleted = 0 AND car_id NOT IN ( SELECT car_id  FROM product WHERE product_type = 2 AND source = 2)  
AND (seller_id = 100)    
    union all     
    SELECT count(1) as a FROM car WHERE is_deleted = 0 AND car_id NOT IN (SELECT car_id  FROM product WHERE product_type = 2 AND source = 2)
AND creator = 1000  AND seller_id = -1
) t


查看执行计划:

6-2.png


改写之后,union的2个SQL片段分别使用了2个不同的索引,扫描的行数分别是1238和7130,比改写之前的扫描16万行记录提升了一个数量级。


总结

虽然数据库的优化器非常强大,但是在有的场景下,改写SQL能帮助优化器更好地优化查询语句。也能让执行计划更稳定。



相关文章

Golang new and make

Go  语言中 new 方法和 make 方法,都是用于分配相应类型内存空间。1、makemake 内置函数分配并初始化(仅)slice、map 或 chan 类型的对象,返回值是所创建的类型本身。与...

HBase导出表和备份表操作

HBase导出表和备份表操作

HBase提供了几种导出数据的方式,包括使用HBase自带的工具和使用HBase的API。本文主要是讲的使用HBase自带的工具进行导出首先我们创建一个表 插入一些数据hbase shelllistc...

hive部署

安装前准备修改环境变量vi /etc/profile 添加内容如下:(hive节点都要执行)export HIVE_HOME=/opt/hiveexport PATH=$PATH:$HIVE_HOME...

trino组件对接hudi(四)

trino组件对接hudi(四)

安装部署本文是基于已经部署了trino组件的环境上,进行的trino和hudi的对接,使trino组件能够正常查询hudi表。1、增加hudi connector配置在trino安装部署下的etc/c...

Hbase 存储相关知识

1.Hbase的写流程Client 写入-> 存入MemStore,一直到MemStore 满-> Flush 成一个StoreFile,直至增长到一定阈值-> 触发Compact...

flink集成iceberg访问hive catalog任务报错

flink集成iceberg访问hive catalog任务报错

问题现象flink在集成iceberg后访问hive catalog任务无法执行,但flink自身任务正常,iceberg表任务无法执行,报错如下:Caused by: java....

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。