2014-10-20 52 views
3

在一個簡單的測試程序中,我啓動一個事務,創建一個#temp表和兩個索引,在表中插入一堆行,並提交。爲什麼每個插入一個I/O到臨時表中? sql server

看着任務管理器I/O寫入Sql Server,我發現每個表插入有1個磁盤寫入。這令我感到驚訝,因爲#temp表格不可恢復,所以除非存在內存壓力,否則不需要編寫或日誌記錄,即使需要記錄日誌,我也希望進行最少量的日誌寫入操作,而不是每次插入1次。相反,使用20,000個插入,我可以獲得20,000個I/O。

引擎有很多內存,沒有來自其他應用程序的壓力。

這裏可以減少I/O數量嗎?

下面的代碼的(處置等爲簡潔移除)主旨

var conn = new SqlConnection("my connection string"); 
conn.Open(); 
tran = conn.BeginTransaction(); 
var cmd = new SqlCommand("create table #sqltt(Context int, intValue int, stringValue varchar(100))", conn, tran)) 
cmd.ExecuteNonQuery(); 
// repeat the above sqlcmd pattern to create two indexes on the table 
// then 
cmd = new SqlCommand("INSERT INTO #sqltt (Context, intValue) VALUES ('-1', @intValue)", conn, tran)) 
var parm = cmd.CreateParameter(); 
parm.DbType = DbType.Int32; 
parm.Direction = ParameterDirection.Input; 
parm.ParameterName = "intValue"; 
for (var i = 0; i < HOWMANY; i++) 
{ 
    parm.Value = i; 
    cmd.ExecuteNonQuery(); 
} 
tran.Commit(); 
conn.Close(); 
+0

您究竟確定了寫入次數?事實上,你應該會看到比這裏的查詢少得多的IO。 – usr 2014-10-20 21:02:43

+0

檢查進程監視器或'sys.dm_io_virtual_file_stats' – 2014-10-20 22:09:40

+0

啊,謝謝你,馬丁,揭示了我的錯誤。我使用每個Sql Server的任務管理「I/O Writes」進行測量,但該計數器包含所有I/O,包括網絡。 (我知道這一次!)使用進程監視器,我看到27次寫入日誌文件,總計大約1.4MB,這是每個插入行平均75字節,這似乎是合理的。發佈作爲答案,我會接受它。 – 2014-10-21 02:00:52

回答

0

我使用每個Sql Server的任務管理「I/O Writes」進行測量,但該計數器包括包括網絡在內的所有I/O。見上面的評論,謝謝Martin。

1

是,通過在單個事務中分批多個插入。每個事務至少需要一個日誌文件寫入 - 對於tempdb,對於任何其他數據庫都是如此,因爲儘管無法恢復,但對tempdb的操作在需要時仍需要一致性和持久性。 tempdb是「全部在內存中」或「不需要I/O」是一種常見的誤解。 SQL Server確實有一些優化來減少tempdb I/O(就​​像緩存臨時表,所以它們不需要經常重新創建),但事務性I/O的基礎仍然適用。

通過在單個事務中批處理多個插入,可以減少需要等待的順序寫入次數。如果您想要真正的最小化日誌記錄,請使用批量插入。順便說一句,通過在所有插入之後創建索引,而不是之前(除非插入以某種方式依賴並且需要查找),您還將獲得更好的性能。

+1

檢查我的第一句話:這是在一個單一的交易。因此,我對許多I/O感到驚訝。 – 2014-10-20 20:33:39

+1

*是*奇數。你能澄清你的問題,甚至更明確地說明這一點(如果可能,插入實際的代碼)?請注意,我的其餘評論仍然適用 - tempdb肯定需要日誌寫入,內存壓力或不需要。但關於物理寫入,您不會期望每個插入寫入1次。 – 2014-10-20 20:36:15

相關問題