原文地址:https://www.depesz.com/2007/07/05/how-to-insert-data-to-database-as-fast-as-possible/
前段时间我在 postgresql 8.2 中写了一篇关于 values(),() 的文章,说多行插入非常快。
有人说我的基准测试毫无用处,因为我没有考虑交易。
其他人要求我将文本翻译成英文。
所以我决定重做测试,用更多的测试场景,并用英文写出来。这是总结。
起初我使用了什么,我测试了什么以及如何。
我使用了一台linux机器,里面有这些东西:
- cpu: AMD Sempron(tm) 处理器 2600+ (1.6ghz)
- 内存:3GB
- 光盘:4 250gb hitachi sata 光盘(仅使用了一张)
我试图使机器尽可能可预测,因此我停止了所有不必要的守护进程。结果 tar 文件中提供了完整的 ps auxwwf 输出。基本上——有 postgresql、sshd、openvpn、dhclient 和一些 getty。没有 cron、atd、smtpd、httpd 或类似的东西。
然后我写了一个生成测试文件的小程序。我自己不分发测试文件,因为它们总共使用了将近 70gb!
然后我写了另一个小程序——它基本上运行了所有的测试(3次取平均值)。
全套结果可作为 tar 文件下载,其中包含 10598 个文件(tar 文件为 350k,解压后的目录需要 42megs)。
一个非常重要的通知。我执行的所有测试都将随机数据插入到此结构的表中:
- id int4 主键,
- some_text 文本,
- bool_1 布尔值,
- bool_2 布尔值,
- some_date 日期,
- some_timestamp 时间戳
所以结果(尤其是没有进一步增益的“断点”)在插入另一个表时会有所不同。这个基准测试的唯一要点是显示哪种方法可以给出哪些结果。以及真正值得麻烦的是什么从一些角度来看,我测试了标准 postgresql 中可用的最快方式——复制,而最慢的方式——大量单行插入,没有事务,没有准备。
复制数据:
- 17.02 秒
- 1451 cpu 在用户模式下
- 191 cpu 在系统模式下
- iowait 中的 20.67 cpu
(CPU 单元是“USER_HZ”,如 linux 内核文档中的 filesystems/proc.txt.gz 文件中所述)。
简单的插入:
- 622.66 秒
- 43208 cpu 处于用户模式
- 14175 cpu 处于系统模式
- iowait 中的 64.33 cpu
哇。这是相当不同的复制时间大约是插入时间的 2%。我想知道我们可以用不同的插入物得到多接近这 2%。
所以,让我们看看如果我使用事务会变得更好。
正如我们所看到的,使用事务可以将处理速度提高到 425-430 秒左右。这提供了大约 32% 的提升。cpu使用率如何?
从图中我可以推断出 iowaits 在某种程度上是随机的,所以我不会在下一个图表中显示它们(毕竟,我真正对总时间感兴趣)。
最大的收益体现在系统 CPU 使用率上。原因?我有一些理论,但没有一个是基于确凿的事实
无论如何 - 似乎通过在事务中放入 25 个插入来获得可观的收益。在此之上 - 仍有一些收益,但不是很明显。
好的,现在让我们检查一下准备插入语句是否会带来任何好处。
它肯定更快。让我们看看加速:
(百分比是针对最简单的插入,没有准备,没有事务)。
可以看出,添加准备会节省一些时间和一些 cpu 使用率,所以这显然是个好主意。使用 prepare 和 inserts 我们可以将时间减少到原始时间的 60% 左右。这还不错。
可以做的最后一件事是使插入在一次调用中插入更多行。
因为我们知道准备工作很好,所以我将只显示准备好的语句的结果。
不同的行显示单个语句插入的不同行数。
这张图片显示(我希望如此)(就像简单的插入一样)交易奖励只持续一段时间——每笔交易最多 25 条语句。
如果向单个语句添加额外的行没有进一步的好处,那又如何呢?
不同的行显示每个事务的不同数量的语句。
每次插入多行时,没有明确的“加速结束”。至少在这个测试中没有。
所以,让我们做一个总结。
- 复制在 17.02 秒内完成了这项工作
- 最简单的插入在 622.66 秒内完成
- 在事务中对插入进行分组的最佳方法是每个事务 80 次插入,它使用了 426.81 秒
- 在自动提交模式下准备好的插入在 545.23 秒内完成了这项工作
- 在事务中对准备好的插入进行分组的最佳方法——每个事务也有 80 个插入,使用时间为 348.38 秒。
- 最简单的多行插入(每次插入 5 行,没有准备好的语句,自动提交)在 164 秒内完成了这项工作
- 插入多行的最佳方法是每个语句使用 100 行,每个事务 100 条语句,使用准备好的语句——它在 37.73 秒内完成了工作。
- 最好的多行插入,没有事务或准备好的语句——每条语句 100 行。使用时间 – 42.07 秒!
所以,如果你想尽可能快地插入数据——使用复制(或者更好——pgbulkload)。如果由于某种原因您不能使用复制,则使用多行插入(8.2 中的新功能!)。然后如果可以的话,将它们捆绑在事务中,并使用准备好的事务,但通常——它们不会给你太多。
所有其他数据——请查看带有结果的电子表格(openoffice 格式,42k










