NOT IN、JOIN、IS NULL、NOT EXISTS效率對比
語句一:select count(*) from A where A.a not in (select a from B)
語句二:select count(*) from A left join B on A.a = B.a where B.a is null
語句三:select count(*) from A where not exists (select a from B where A.a = B.a)
知道以上三條語句的實際效果是相同的已經很久了,但是一直沒有深究其間的效率對比。一直感覺上語句二是最快的。
今天工作上因為要對一個數千萬行資料的庫進行資料清除,需要刪掉兩千多萬行資料。大量的用到了以上三條語句所要實現的功能。本來用的是語句一,但是結果是執行速度1個小時32分,日誌檔案佔用21GB。時間上雖然可以接受,但是對硬碟空間的佔用確是個問題。因此將所有的語句一都換成語句二。本以為會更快。沒想到執行40多分鐘後,第一批50000行都沒有刪掉,反而讓SQL SERVER崩潰掉了,結果令人詫異。試了試單獨執行這條語句,查詢近一千萬行的表,語句一用了4秒,語句二卻用了18秒,差距很大。語句三的效率與語句一接近。
第二種寫法是大忌,應該儘量避免。第一種和第三種寫法本質上幾乎一樣。
假設buffer pool足夠大,寫法二相對於寫法一來說存在以下幾點不足:
(1)left join本身更耗資源(需要更多資源來處理產生的中間結果集)
(2)left join的中間結果集的規模不會比表A小
(3)寫法二還需要對left join產生的中間結果做is null的條件篩選,而寫法一則在兩個集合join的同時完成了篩選,這部分開銷是額外的
這三點綜合起來,在處理海量資料時就會產生比較明顯的區別(主要是記憶體和CPU上的開銷)。我懷疑樓主在測試時buffer pool可能已經處於飽和狀態,這樣的話,寫法二的那些額外開銷不得不借助磁碟上的虛擬記憶體,在SQL Server做換頁時,由於涉及到較慢的I/O操作因此這種差距會更加明顯。
關於日誌檔案過大,這也是正常的,因為刪除的記錄多嘛。可以根據資料庫的用途考慮將恢復模型設為simple,或者在刪除結束後將日誌truncate掉並把檔案shrink下來。
因為以前曾經作過一個對這個庫進行無條件刪除的指令碼,就是要刪除資料量較大的表中的所有資料,但是因為客戶要求,不能使用truncate table,怕破壞已有的庫結構。所以只能用delete刪,當時也遇到了日誌檔案過大的問題,當時採用的方法是分批刪除,在SQL2K中用set rowcount @chunk,在SQL2K5中用delete top @chunk。這樣的操作不僅使刪除時間大大減少,而且讓日誌量大大減少,只增長了1G左右。
但是這次清除資料的工作需要加上條件,就是delete A from A where ....後面有條件的。再次使用分批刪除的方法,卻已經沒效果了。
不知您知不知道這是為什麼。
語句二:select count(*) from A left join B on A.a = B.a where B.a is null
語句三:select count(*) from A where not exists (select a from B where A.a = B.a)
知道以上三條語句的實際效果是相同的已經很久了,但是一直沒有深究其間的效率對比。一直感覺上語句二是最快的。
今天工作上因為要對一個數千萬行資料的庫進行資料清除,需要刪掉兩千多萬行資料。大量的用到了以上三條語句所要實現的功能。本來用的是語句一,但是結果是執行速度1個小時32分,日誌檔案佔用21GB。時間上雖然可以接受,但是對硬碟空間的佔用確是個問題。因此將所有的語句一都換成語句二。本以為會更快。沒想到執行40多分鐘後,第一批50000行都沒有刪掉,反而讓SQL SERVER崩潰掉了,結果令人詫異。試了試單獨執行這條語句,查詢近一千萬行的表,語句一用了4秒,語句二卻用了18秒,差距很大。語句三的效率與語句一接近。
第二種寫法是大忌,應該儘量避免。第一種和第三種寫法本質上幾乎一樣。
假設buffer pool足夠大,寫法二相對於寫法一來說存在以下幾點不足:
(1)left join本身更耗資源(需要更多資源來處理產生的中間結果集)
(2)left join的中間結果集的規模不會比表A小
(3)寫法二還需要對left join產生的中間結果做is null的條件篩選,而寫法一則在兩個集合join的同時完成了篩選,這部分開銷是額外的
這三點綜合起來,在處理海量資料時就會產生比較明顯的區別(主要是記憶體和CPU上的開銷)。我懷疑樓主在測試時buffer pool可能已經處於飽和狀態,這樣的話,寫法二的那些額外開銷不得不借助磁碟上的虛擬記憶體,在SQL Server做換頁時,由於涉及到較慢的I/O操作因此這種差距會更加明顯。
關於日誌檔案過大,這也是正常的,因為刪除的記錄多嘛。可以根據資料庫的用途考慮將恢復模型設為simple,或者在刪除結束後將日誌truncate掉並把檔案shrink下來。
因為以前曾經作過一個對這個庫進行無條件刪除的指令碼,就是要刪除資料量較大的表中的所有資料,但是因為客戶要求,不能使用truncate table,怕破壞已有的庫結構。所以只能用delete刪,當時也遇到了日誌檔案過大的問題,當時採用的方法是分批刪除,在SQL2K中用set rowcount @chunk,在SQL2K5中用delete top @chunk。這樣的操作不僅使刪除時間大大減少,而且讓日誌量大大減少,只增長了1G左右。
但是這次清除資料的工作需要加上條件,就是delete A from A where ....後面有條件的。再次使用分批刪除的方法,卻已經沒效果了。
不知您知不知道這是為什麼。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16436858/viewspace-612029/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mysql的left join和inner join的效率對比,以及如何優化MySql優化
- in/exists和not in/not exists執行效率
- 【SQL】Oracle sql語句 minus函式執行效率與join對比SQLOracle函式
- 透過sql trace比較常規 not in 、minus、not exists效率SQL
- 通過sql trace比較常規 not in 、minus、not exists效率SQL
- MySQL exists 優化 in 效率MySql優化
- in,exists和not exists ,not in與null的一些關係記載Null
- 對IN & EXISTS NOT IN & NOT EXISTS的優化優化
- MySQL批量insert效率對比SQL
- in、exists操作與null的一點總結Null
- oracle sql_not exists與null的測試OracleSQLNull
- 使用exists(Semi-Join)優化distinct語句優化
- 深入理解PHP之isset和array_key_exists對比PHP
- 【C#】反射的用法及效率對比C#反射
- IOS各種集合遍歷效率對比iOS
- rebuild與rebuild online效率比對Rebuild
- [Oracle] minus 和 not exists比較Oracle
- ORACLE 中IN和EXISTS比較Oracle
- not in 和 not exists 比較和用法
- string中Insert與Format效率對比、String與List中Contains與IndexOf的效率對比ORMAIIndex
- Transformation之NUll-aware Anti-join(NAAJ)【九】ORMNull
- HASH JOIN ,MERGE JOIN ,NESTED LOOP的比較OOP
- 關於ORACLE MYSQL NOT IN和NOT exists需要注意的 NULL值OracleMySqlNull
- (轉)ORACLE 中IN和EXISTS比較Oracle
- NULL列時,如何使得IS NULL或者IS NOT NULL可以使用索引來提高查詢效率Null索引
- MYSQL 中 exists 語句執行效率變低MySql
- List中對比Contains, Exists, Any之間的優缺點AI
- Oracle優化案例-用left join代替反連線 not in not exists(十)Oracle優化
- 對Join的理解
- 資料庫執行效率的對比測試資料庫
- sqlserver 檢視和sql語句的效率對比SQLServer
- 11g優化器增加Null aware anti join優化Null
- mysql update join優化update in查詢效率MySql優化
- pl/sql中三種遊標迴圈效率對比SQL
- oracle10g表壓縮後的效率比對Oracle
- 淺談Oracle中exists與in的執行效率問題Oracle
- python多執行緒爬蟲與單執行緒爬蟲效率效率對比Python執行緒爬蟲
- 資料結構-各種排序演算法效率對比圖資料結構排序演算法