zoukankan      html  css  js  c++  java
  • (转)SQL中使用or影响性能的解决办法

    原文地址:https://www.cnblogs.com/xuxiaona/p/4962727.html

    近期做了一个存储过程,执行时发现非常的慢,竟然需要6、7秒!

    经排查,发现时间主要都耗在了其中一段查询语句上。这个语句用于查出结构相同的两个表中,其中两个字段的任一个字段数据相同的记录。

    例如,A表的结构如下所示:

    --会员表
    CREATE Table Member
    (      
    MemberID int, --会员ID MemberName varchar(50), --会员姓名 MemberPhone varchar(50) --会员电话 ) go

    B表的结构与A表完全相同,假设表名为Member_Tmep。

    现在Member表中有7000条不重复的数据,Member_Tmep表中有2000条数据,需要查出这两张表中,会员姓名或会员电话相同,但会员ID不相同的记录。

    按照普通的逻辑,我一开始是这样写的:

    select a.MemberID,a.MemberName,a.MemberPhone
        from Member a,Member_Tmep b 
        where (a.MemberName = b.MemberName or a.MemberPhone = b.MemberPhone) and a.MemberID <> b.MemberID
      

    这条语句看上去逻辑很清晰,写出来也很简洁,但执行起来为什么却那么耗费时间呢?

    虽然我不清楚这条语句错在哪里,但也想到试着用另一种方式来实现这个查询,于是我把这段查询语句改成了下面这样:

    --查询出会员姓名相同但ID不同的记录
    select a.MemberID,a.MemberName,a.MemberPhone
        from Member a
        inner join Member_Tmep b on a.MemberName = b.MemberName and a.MemberID <> b.MemberID
    
    union
    
    --再查询出会员电话相同但ID不同的记录,进行合并
    select a.MemberID,a.MemberName,a.MemberPhone
        from Member a
        inner join Member_Tmep b on a.MemberPhone = b.MemberPhone and a.MemberID <> b.MemberID

    这样再执行,秒秒钟就执行完了。

    其实之前也写过很多类似第一种写法的SQL语句,一直没出过这种问题,那是因为数据量没有这么大。

    应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描。而改用union之后,性能就大大提高了。

    使用"union all"的性能比"union"更高一些。因为当SQL 语句需要UNION两个查询结果集合时,这两个结果集合会以UNION-ALL的方式被合并, 然后在输出最终结果前进行排序。 如果用UNION ALL替代UNION, 这样排序就不是必要了,效率就会因此得到提高。

    而在上面这个例子里使用"union"而不是"union all",是因为“会员姓名相同但ID不同的记录”和“会员电话相同但ID不同的记录”可能有重复,使用"union"可以去掉重复的记录

    其实这个道理之前也有看到过,但是在编写语句的时候经常习惯性的就用了简洁的or语句,慢慢也就忘了这回事了。。。

    除了上述这种情况,还有一种常见的会使用or语句的情景,那就是:查询出某字段的值等于某几个特定值的记录。

    例如,需要查询出会员姓名为“张三”、“李四”的记录。我们可能会这样写:

    select * from Member where MemberName = '张三' or MemberName = '李四'

    通常情况下,这种写法是看不出有什么问题的,但是在数据量很大的情况下,一样会非常影响执行速度。

    还有一种写法是使用in语句,例如下面这样:

    select * from Member where MemberName in ('张三','李四')

    但是有些说法认为in语句一样会导致全表扫描。in和not in的写法都是应该尽量避免的。

    如果需要查询的特定值是连续的数值范围,如90--100,可以改用bwteen...and语句。例如:

    select * from Member where MemberID between 90 and 100

    如果无法使用bwteen...and,那么仍然需要使用union方法了,如:

    select * from Member where MemberName = '张三' 
    union all
    select * from Member where MemberName = '李四'

    这里因为会员姓名为“张三”的和为“李四”的不可能有重复记录,因此可以使用性能更高的union all,而不是union了。

  • 相关阅读:
    Faster rcnn代码理解(2)
    Faster rcnn代码理解(1)
    BN讲解(转载)
    faster-rcnn
    编程修养
    人才盘点
    Source Insight 技巧总结
    使用DNSSCrypt解决DNS污染问题
    程序员的自我修养 学习笔记(5)
    闯红灯检测原理
  • 原文地址:https://www.cnblogs.com/ooip/p/7813644.html
Copyright © 2011-2022 走看看