2014-10-20 44 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

相关问题