SQL中使用or影響性能的解決辦法


近期做了一個存儲過程,執行時發現非常的慢,竟然需要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了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM