负载下插入性能提高:为什么?


19

我有一段代码可以对高度非规范化的表执行插入操作。这些表的列数范围从〜100到300+。这是在Windows Server 2008上运行的SQL Server 2008 R2。

每个插入包括在同一事务下插入多个表。有些插入是由NHibernate批处理的,但是有些不能,但是它们都在同一事务下。

当我通过重复调用一段执行插入的代码执行了500次插入操作时,平均得到的时间约为360毫秒。

奇怪的是,当我使用4个进程同时运行测试代码(在Windows Server 2008下从4个不同的命令提示符运行同一个exe)时,每次调用的插入性能会好得多。我看到突发速度高达90毫秒(几乎快了X4)。我正在从代码中测量插入时间。

由于4个进程彼此之间一无所知,因此我假设这与SQL Server有关,但是我绝对不知道为什么。我想知道为什么会这样,以及是否有任何配置可以使我在插入频率不那么高的情况下获得相同的性能。

同样欢迎提出有关SQL Server监视方法的建议,以了解数据库级别的情况。

Answers:


15

一个可能的原因是,四个并发进程生成了更有利的日志刷新模式-通常意味着与单个执行进程相比,每个日志刷新写入更多的数据。

要确定事务日志吞吐量/刷新大小是否是一个因素,请监视:

寻找内部限制。在SQL Server 2008 R2中,在64位版本上,每个数据库最多可以有32个未完成(异步)日志刷新I / O(在32位上只有8个)。未完成IO的总大小限制为3840KB。

更多信息和进一步阅读:


12

@PaulWhite所说的一切,再加上...

如果您有外键,则每次插入都将需要对每个引用的表进行检查。在我看来,就像您一样,因为您只有360ms,这对我来说感觉很慢。

无论如何,通过将数据存储在RAM中而不是将其加载到磁盘中,可以极大地帮助检查这些表。

在我看来,将数据加载到RAM中是执行的重要部分,并且只需要执行一次即可。

这也可能是有效的计划缓存,并且您的查询需要首次编译,随后的调用可以避免该阶段。


谢谢罗伯。我的性能问题与插入期间使用的表数量过多有关。没有外键,出于性能原因,我将其删除,并且我的模型和域要求允许我这样做。我没有将数据加载到RAM,并且插入的内容始终受到传入请求的动态影响,这些请求一直在变化。我基本上是将星型/雪花(ish)模式误用于OLTP,并试图摆脱可能的最佳性能。
mahonya

2
@mahonya,即使您没有将数据显式加载到RAM中,SQL Server在执行插入操作之前也必须首先将所需的索引和数据页读入缓冲区缓存。并发插入线程可能具有预热缓存的作用,以使一个线程产生读取开销,而另一个线程访问缓存中的数据。
Dan Guzman

感谢@DanGuzman-是的,mahonya,您的缓存很有可能被很好地加热。我会检查您的等待,看看是否是导致瓶颈的物理I / O。
罗布·法利

感谢@DanGuzman Agreed,我习惯在PostgreSQL中看到db索引缓存加速,这可能是我误解了Rob的输入。
mahonya '16

-3

一些服务器/ CPU /操作系统会记住模式。像快取

由于您做过4次相同的事情,所以我确信有很多方法可以偷工减料,我猜测您做的第一种方法是将其视为一个漫长的过程(example1),而第二种方法是是看到重用的代码并像缓存一样运行它(example2),或者它可能是第一个过程要使其全部适应(ram example3)。

范例1:0111110000110111110000111011111000011110111110000

example2:0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

example3:0111110000011111000001111100000111110000 example3:循环:0111110000

我知道ubuntu服务器通过重复的mysql查询来做到这一点。我可以将它们保存在缓存中,尽管实际上唯一的时间差是10至40毫米,但这加起来了。当我在学校时,有一些课程表明您必须使程序(perl / php)使用该缓存更快。

但是,它可能取决于程序,它是什么语言,它是用什么语言编写的或如何编程的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.