我的编程空间,编程开发者的网络收藏夹
学习永远不晚

MySQL避免索引列使用 OR 条件

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

MySQL避免索引列使用 OR 条件

这个亏已经吃过很多次了,在开发以前的sql代码里面,许多以 or 作为where条件的查询,甚至更新。这里举例来说明使用 or 的弊端,以及改进办法。

select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and (f_mobile ='1234567891' or f_phone ='1234567891' ) limit 1

从查询语句很容易看出,f_mobile和f_phone两个字段都有可能存电话号码,一般思路都是用 or 去一条sql解决,但表数据量一大简直是灾难:

t_tbanme1上有索引 idx_id_mobile(f_xxx_id,f_mobile) , idx_phone(f_phone) , idx_id_email(f_id,f_email) ,explain 的结果却使用了 idx_id_email 索引,有时候运气好可能走 idx_id_mobile f_xxx_id

因为mysql的每条查询,每个表上只能选择一个索引。如果使用了 idx_id_mobile 索引,恰好有一条数据,因为有 limit 1 ,那么恭喜很快得到结果;但如果 f_mobile 没有数据,那 f_phone 字段只能在f_id条件下挨个查找,扫描12w行。 or 跟 and 不一样,甚至有开发认为添加 (f_xxx_id,f_mobile,f_phone) 不就完美了吗,要吐血了~

<!-- more -->

那么优化sql呢,很简单( 注意f_mobile,f_phone上都要有相应的索引 ), 方法一 :

(select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_mobile ='1234567891' limit 1 ) UNION ALL 
(select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_phone ='1234567891' limit 1 )

两条独立的sql都能用上索引,分查询各自limit,如果都有结果集返回,随便取一条就行。

还有一种优化办法,如果这种查询特别频繁(又无缓存),改成单独的sql执行,比如大部分号码值都在f_mobile上,那就先执行分sql1,有结果则结束,判断没有结果再执行分sql2 ,能减少数据库查询速度,让代码去处理更多的事情, 方法二 伪代码:

sql1 = select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_mobile ='1234567891' limit 1;
sq1.execute();
if no result sql1:
  sql1 = select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_phone ='1234567891' limit 1;
    sql1.execute();

复杂一点的场景是止返回一条记录那么简单,limit 2:

select a.f_crm_id from d_dbname1.t_tbname1 as a where (a.f_create_time > from_unixtime('1464397527') or a.f_modify_time > from_unixtime('1464397527') ) limit 0,200

这种情况方法一、二都需要改造,因为 f_create_time,f_modify_time 都可能均满足判断条件,这样就会返回重复的数据。

方法一需要改造:

(select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_create_time > from_unixtime('1464397527') limit 0,200 ) UNION ALL
(select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_modify_time > from_unixtime('1464397527') and a.f_create_time <= from_unixtime('1464397527') limit 0,200 )

有人说 把 UNION ALL 改成 UNION 不就去重了吗?如果说查询比较频繁,或者limit比较大,数据库还是会有压力,所以需要做trade off。

这种情况更多还是适合方法二,包括有可能需要 order by limit 情况。改造伪代码:

sql1 = (select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_create_time > from_unixtime('1464397527') limit 0,200 );
sql1.execute();
sql1_count = sql1.result.count
if sql1_count < 200 :
  sql2 = (select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_modify_time > from_unixtime('1464397527') and a.f_create_time <= from_unixtime('1464397527') limit 0, (200 - sql1_count) );
  sql2.execute();

final_result = paste(sql1,sql2);

or条件在数据库上很难优化,能在代码里优化逻辑,不至于拖垮数据库。只有在 or 条件下无需索引时(且需要比较的数据量小),才考虑。

相同字段 or 可改成 in,如 f_id=1 or f_id=100 -> f_id in (1,100) 。 效率问题见文章 mysql中or和in的效率问题 。

上述优化情景都是存储引擎在 InnoDB 情况下,在MyISAM有不同,见 mysql or条件可以使用索引而避免全表 。

来自: https://segmentfault.com/a/1190000005644978

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

MySQL避免索引列使用 OR 条件

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

MySQL避免索引列使用 OR 条件

这个亏已经吃过很多次了,在开发以前的sql代码里面,许多以 or 作为where条件的查询,甚至更新。这里举例来说明使用 or 的弊端,以及改进办法。select f_crm_id from d_dbname1.t_tbname1 wher
2022-05-25

mysql多条件查询会使用索引吗

mysql多条件查询会使用索引,取决因素有:1、索引的选择性,指索引中具有唯一或较小重复值的比例;2、索引的覆盖度,指索引中包含了查询所需的所有列,从而避免了对实际数据行的访问,提高查询性能;3、查询的顺序和条件结合,根据查询的具体情况进行
2023-07-25

SQL Server优化技巧——如何避免查询条件OR引起的性能问题

之前写过一篇博客“SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析”,里面介绍了OR可能会引起全表扫描或索引扫描的各种案例,以及如何优化查询条件中含有OR的SQL语句的几种方法,其实还有一些方法可以用来优化这种问题,这里简单介绍一下。   如下所示
SQL Server优化技巧——如何避免查询条件OR引起的性能问题
2017-06-21

尽量避免使用索引合并的场景问题解析

目录引言1. 问题重现2. 索引合并2.1 Using intersect(...)2.2 Using union(...)2.3 Using sort_union(...)2.4 索引合并原理3. 索引合并的问题引言在前面的文章中,松哥
2023-05-15

MySQL组合索引(多列索引)使用与优化案例详解

目录1、多列索引2、测试案例及过程2.1 创建一个测试数据库和数据表2.2 添加两个单列索引2.3 查询一条数据利用到两个列的索引2.4 查看执行计划2.5 然后删除以上索引,添加多列索引2.6 再次查询3、多列索引的使用顺序3.1 怎么选
2022-07-04

Pytorch使用tensor特定条件判断索引的方法

本篇内容介绍了“Pytorch使用tensor特定条件判断索引的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!torch.where()
2023-06-14

MySQL 隔离数据列和前缀索引的使用总结

目录隔离数据列前缀索引和索引的选择性隔离数据列通常,我们会发现查询语句会妨碍MySQL使用索引。除非在查询语句中列是独立的,否则MySQL不会使用这些列的索引。“隔离”的意思是索引列不应该成为表达式的一部分或者在一个查询函数体中。例如下面的
2022-05-20

mysql条件查询and or使用方法及优先级实例分析

本文实例讲述了mysql条件查询and or使用方法及优先级。分享给大家供大家参考,具体如下: mysql and与or介绍 AND 和 OR 可在 WHERE 子语句中把两个或多个条件结合起来。 使用OR关键字时:只要符合这几个查询条件的
2022-05-15

如何查询sql语句的条件字段是否使用了索引以及跳过索引的几种情况

今天执行通过时间范围查询订单数量的sql时,想看看该时间字段是否走了索引,发现一个很有意思的问题.首先说一下查询是否使用了索引的方法通过explain来查看,即将explain放在查询的sql前面explain SELECT * from ord_order_
如何查询sql语句的条件字段是否使用了索引以及跳过索引的几种情况
2021-09-24

编程热搜

目录