如何从<my language =“”>加速INSERT到<my dbms =“”> SQL数据库?</my> </my>

时间:2014-02-12 21:21:13

标签: mysql sql sqlite postgresql orm

关于加速INSERT到SQL数据库的问题有很多问题,例如thisthisthisthis和(我最喜欢的){ {3}}。许多问题伪装成语言依赖,但问题通常会缩小为:

哪些常规技术会将我的[特定语言]程序中的INSERTS加速到我的[特定DBMS] SQL数据库中?

1 个答案:

答案 0 :(得分:3)

INSERTS期间最大的低效率来自两个来源:单个数据事务需要时间,而语言和数据库之间的ORM适配器并不总是特别有效。

这个答案使用Ruby On Rails作为示例语言,但此处显示的技术几乎适用于任何具有底层数据库接口的高级语言。

结论(TL; DR)

通过下面列出的任何批量插入方法一次插入500条记录可以使您的加速超过20倍。通过调整,可能会变得更高。

测试

让我们从123001记录的内存数组开始。 (这些来自[多伦多运输数据集市]的“trips.txt”文件。1

dataset = Utilities.load_csv(Rails.root.join("datasets", "trips.txt")

基线:一次一个插入

在Ruby On Rails中,你可以这样做:

dataset.each {|record| Trip.create!(record) }

基本上转换为123,000个单独的SQL调用形式:

INSERT INTO "trips" (<column_names>) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [<column name/value pairs>]
(123000 more times...)

加速1:包含在交易中

这几乎相同,但将内部循环包装在单个SQL事务中:

begin transaction
INSERT INTO "trips" (<column_names>) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)  [<column name/value pairs>]
(123000 more times...)
commit transaction

加速2:批量INSERT版本A

这个将原始数组分成500个批次(以避免限制SQLite和潜在的字符串缓冲区大小),其中每个事务都有以下形式:

INSERT INTO trips (comma_separated_column_names) VALUES
    (comma_separated_values_for_row_1),
    (comma_separated_values_for_row_2),
    ...
    (comma_separated_values_for_row_500);
... repeated 246 times

加速3:批量INSERT版本B

某些DBMS不支持批量INSERT版本A(特别是旧版本的SQLite)的语法。以下表单在功能上是相同的,并且受到许多数据库的支持(尽管不严格遵循SQL-92):

     INSERT INTO trips (comma_separated_column_names)
          SELECT comma_separated_values_for_row_1
UNION ALL SELECT comma_separated_values_for_row_2
...
UNION ALL SELECT comma_separated_values_for_row_500
...repeated 246 times

加速4:DBM特定方法

正如https://stackoverflow.com/users/20860/bill-karwin指出的那样,人们可以

  例如,

利用特定于供应商的批量加载命令   用于MySQL的LOAD DATA INFILE,用于PostgreSQL的COPY或用于SQL的SQL * Loader   Oracle等每个品牌都有自己的命令或工具,所以没有   供应商中立的方式,但这些方法往往有一个   数量级更好的性能,所以不应该   忽视。

虽然这些不是通用技术,但它们在特定情况下会很有用。我们没有在下面的测试中对这些中的任何一个进行基准测试。

相对加速

我们在MySQL,PostgreSQL和SQLite中测试了上面显示的各种技术。下面的数字显示了相对于基线情况的各种方法的速度。第一个数字是相对用户+系统时间,(括号)中的数字是相对经过时间。

(注意:我选择不显示绝对时间,因为这不是关于哪个数据库最快的讨论 - 有太多变量可以做出合理的声明。如果轻推,我会发布两个代码github你可以运行自己的测试并得出你自己的结论。)

的MySQL

  • 包含在交易中:1.2x(1.4x)
  • 批量INSERT版本A:24.3x(19.0x)
  • 批量INSERT版本B:24.3x(17.1x)

的PostgreSQL

  • 包含在交易中:1.2x(1.6x)
  • 批量INSERT版本A:27.2x(16.7x)
  • 批量INSERT版本B:27.2x(13.9x)

SQLite的

  • 包含在交易中:1.6x(2.4x)
  • 批量INSERT版本A:25.8x(24.7x)
  • 批量INSERT版本B:24.1x(34.1x)

测试笔记

Processing environment: 2.66 GHz Intel Core i7, 8GB 1067 MHz DDR3
Operating System: OS X v 10.9.5 
Ruby version: 2.0.0 (64 bit) 
Rails version: 4.0.2 
MySQL: Server version: 5.1.49  
PostgreSQL: psql (9.3.1, server 8.3.14) 
SQLite: SQLite version 3.7.12 2012-04-03 19:43:07