原文地址:https://www.cnblogs.com/xuxiaona/p/4962727.htmlhtml
近期作了一個存儲過程,執行時發現很是的慢,居然須要六、7秒!性能
經排查,發現時間主要都耗在了其中一段查詢語句上。這個語句用於查出結構相同的兩個表中,其中兩個字段的任一個字段數據相同的記錄。code
例如,A表的結構以下所示:htm
--會員表 CREATE Table Member (
MemberID int, --會員ID MemberName varchar(50), --會員姓名 MemberPhone varchar(50) --會員電話 ) go
B表的結構與A表徹底相同,假設表名爲Member_Tmep。blog
如今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
這條語句看上去邏輯很清晰,寫出來也很簡潔,但執行起來爲何卻那麼耗費時間呢?io
雖然我不清楚這條語句錯在哪裏,但也想到試着用另外一種方式來實現這個查詢,因而我把這段查詢語句改爲了下面這樣:class
--查詢出會員姓名相同但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了。