例如,我运行了在this page上找到的脚本,除了我在循环周围添加了一个BEGIN TRAN和COMMIT.充其量我可以看到磁盘使用率达到7Mb / s,而cpu几乎没有达到5%.服务器已安装64Gb并使用10.第一次呼叫的总运行时间为2分15秒,后续呼叫约为1分钟.数据库处于简单恢复状态,在测试期间处于空闲状态.我在每次通话之间放下了桌子.
为什么这么简单的脚本这么慢?几乎没有使用硬件.专用磁盘基准测试工具和sqlIO都表明SSD可以正确执行,读取和写入速度都高达500Mb / s.我知道随机写入比顺序写入慢,但我希望像这样的简单插入到没有聚簇索引的表,要快得多.
最终我们的场景要复杂得多,但我觉得我需要先了解一个简单的案例.简而言之,我们的应用程序删除旧数据,然后使用sqlBulkCopy将新数据复制到登台表,执行一些过滤,最后根据情况使用MERGE和/或INSERT INTO将数据复制到最终表.
– >编辑1:我按照Martin Smith链接的程序,得到了以下结果:
[Wait Type] [Wait Count] [Total Wait (ms)] [T. Resource Wait (ms)] [T. Signal Wait (ms)] NETWORK_IO 5008 46735 46587 148 LOGBUFFER 901 5994 5977 17 PAGELATCH_UP 40 866 865 1 SOS_SCHEDULER_YIELD 53279 219 121 98 WRITELOG 5 145 145 0 PAGEIOLATCH_UP 4 58 58 0 LATCH_SH 5 0 0 0
我发现很奇怪NETWORK_IO占用大部分时间,考虑到没有结果显示,除了sql文件之外没有数据要传输到任何地方. NETWORK_IO类型是否包含所有IO?
– >编辑2:我创建了一个20Gb RAM磁盘并从那里安装了一个数据库.我在SSD上的最佳时间是48秒,RAM磁盘下降到37秒. NETWORK_IO仍然是最大的等待. RAM磁盘的最大写入速度约为250Mb / s,而它能够达到每秒几千兆字节.它仍然没有使用太多的cpu,那么是什么阻碍了sql?
解决方法
在没有看到任何资源瓶颈的情况下达到性能上限的主要原因是因为您已经达到了在一个会话单线程中可以处理的限制.循环不是并行处理的,但所有插入都是串行完成的.
就我而言,插入300万行需要36秒.这意味着每行36/30000000 = 0.000012秒.那很快.在我的系统上,只需要0.000012就可以完成所有必要的步骤.
使其更快完成的唯一方法是并行启动第二个会话.
如果我并行启动2个会话,则会执行1500万次插入.两人都在18秒内完成.我可以扩展更多,但我目前的测试设置是通过两个并行会话达到95%cpu,因此做3会使结果产生偏差,因为我会遇到cpu瓶颈.
如果我开始2个并行会话,同时插入300万行,它们都会在39秒内完成.所以现在在39秒内有600万行.
好的,这仍然让我们看到NETWORK_IO等待.
NETWORK_IO等待是通过使用扩展事件来跟踪它们而添加的.在我的情况下,插入需要36秒(平均).当使用扩展事件方式时(从第一个注释中的上面的链接),这是注册的:
Wait Type Wait Count Total Wait Time (ms) Total Resource Wait Time (ms) Total Signal Wait Time (ms) NETWORK_IO 3455 68808 68802 6 PAGEIOLATCH_SH 3 64 64 0 PAGEIOLATCH_UP 12 58 58 0 WRITE_COMPLETION 8 15 15 0 WRITELOG 3 9 9 0 PAGELATCH_UP 2 4 4 0 SOS_SCHEDULER_YIELD 32277 1 0 1 IO_COMPLETION 8 0 0 0 LATCH_SH 3 0 0 0 LOGBUFFER 1 0 0 0
您可以看到已注册68秒的NETWORK_IO.但由于插入循环是一个需要36秒的单线程动作,因此不可能. (是的,使用多个线程,但操作是串行的,从不并行,因此您不能比查询的总持续时间更多地等待更多的等待时间)
如果我不使用扩展事件,而只是在一个安静的实例上使用等待统计数据DMV(只运行插入),我得到:
Wait Type Wait Count Total Wait Time (ms) Total Resource Wait Time (ms) Signal Resource Wait Time (ms) SOS_SCHEDULER_YIELD 8873 0.21 0.01 0.20 PAGEIOLATCH_UP 3 0.02 0.02 0.00 PREEMPTIVE_OS_AUTHENTICATIONOPS 17 0.02 0.02 0.00 PAGEIOLATCH_SH 1 0.00 0.00 0.00
因此,您在扩展事件日志中看到的NETWORK_IO与您的插入循环无关. (如果你不打开nocount,你会有大量的异步网络IO等待,1马丁)
但是我不知道为什么NETWORK_IO出现在扩展事件跟踪中.当然,写出事件的异步文件目标会累积ASYNC_NETWORK_IO,但是肯定这都是在不同的SPID上完成的,然后是我们正在过滤的SPID.我可能会将此问题作为一个新问题