Sql-Server

插入多個查詢是否需要與單個查詢相同的時間?

  • January 15, 2018

我有一個要求,我必須插入很多行。對於插入,我們像這樣使用

insert into emp(name,age) values('abc',12);

這將只插入一行。對於插入多行,我們可以多次編寫插入查詢或編寫具有多個值的單個查詢。例如

條件1

insert into emp(name,age) values('abc1',121);
insert into emp(name,age) values('abc2',122);
insert into emp(name,age) values('abc3',12);

條件2

insert into emp(name,age) values('abc',12),('abc2',122),('abc3',12);

我的問題是上面的(條件1和條件2)都需要時間嗎?我猜條件2比條件2花費的時間少。如果我的猜測是真的,那是什麼原因呢?

至少在 SQL Server 中(不能代表您提到的其他 RDBMS,抱歉),在一定程度上,單個語句將比多個語句更好地擴展。當然,您可以使用您的確切陳述和數據自行測試;這裡沒有人可以用你的具體情況為你測試,你的具體情況可能會以某種方式傾斜。“哪個更快,x 還是 y?” 這里通常不鼓勵提問,因為您可以在自己的環境中測試它們,這比我們任何人向您拋出猜測和邏輯要快得多。特別是當您試圖為您列出的所有數據庫平台找到答案時 - 沒有人是所有這些方面的專家,任何這樣的答案要麼非常有偏見(比如這個),要麼過於籠統而無用.

不過,總的來說,準備單個語句的成本(並且可能根據您的程式碼和提供者的行為單獨發送它們)應該加起來,就像@mustaccio 所說的那樣

如果你要寄三封信,你會帶著三封信去郵局一次,還是帶著一封信去三趟?

如果每個小語句都被分解為單個數據包甚至不同的連接,那麼在您的場景中尤其如此。同樣,我不知道您的提供程序是如何工作的,或者您的程式碼如何發送這些語句 - 如果它是一組可變數量的語句,那麼 SQL Server 實際上比單個單語句批次更難優化,因為 SQL Server在批次級別進行優化。

請注意,該VALUES()子句具有1,000 個值的任意限制,因此您可能需要根據您擁有的值的數量創建多個語句。原因是對編譯時間的擔憂,正如Paul White 在此處解釋的那樣。另請注意:Oracle 也有同樣的限制。

根據Martin Smith 的測試,編譯時間至少是最少的,並且相對不變,最多只有 250 多個值。請參閱這些圖表(有關詳細資訊,請參閱他的回答):

編譯時間1

編譯時間2

編譯時間 3

如果您使用VALUES()子句,請注意每個變體(即實際值集的數量)將生成自己的計劃,無論您是使用正確的參數化語句還是僅使用內聯常量,即使設置了數據庫的參數化設置也是如此簡單。因此,您可能需要考慮使用optimize for ad hoc workloads伺服器設置(此處此處的大量資訊,以防止一次性使用變體填充計劃記憶體(無論如何,對於大多數係統來說,這通常是一個好主意,除非您受 CPU 限制並且編譯成本被證明是過分)。

解決這個問題的一個更好的方法是使用表值參數 (TVP),它允許您通過單個參數發送結構化數據集,從而為您提供一種有效的數據傳遞方式和一個可以重複使用的計劃,而不管傳遞的值的數量。這裡的問題是我不確定 Java 是否理解那些是什麼(在 C# 中,你可以發送一個 DataTable 作為Structured參數)。

對於 SQL Server:兩者都不是。

要插入大量行,您應該使用批量插入 API,並蓬勃發展以實現最少記錄的插入。

可以使用IRowsetFastLoad(OleDB)、使用批量複製函式(ODBC) 或使用SqlBulkCopy(.Net) 來實現批量插入。所有這些 API 的共同點是它們與伺服器建立快速插入管道,然後開始推送行。這些不是 T-SQL 語句,而是 TDS批量載入消息的實現。在更高的抽象層,您可以使用啟用了快速載入選項的bcp.exeBULK INSERT語句或SSIS OleDB 目標。

第二個可選的改進是實現最少的日誌記錄。請參閱可以最少記錄的操作(批量插入可以,普通插入不能)。有關詳細資訊,請閱讀批量導入中最少日誌記錄的先決條件

最後,我敦促您花一些時間閱讀SQL Server 數據載入性能指南

引用自:https://dba.stackexchange.com/questions/90125