(轉)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了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章