Mysql 如何加快插入<;我的数据库管理系统>;来自<;我的语言>;?
关于如何加快SQL数据库的插入速度,有很多问题,例如、、和(我最喜欢的)。许多问题伪装成语言依赖,但问题通常归结为:Mysql 如何加快插入<;我的数据库管理系统>;来自<;我的语言>;?,mysql,sql,sqlite,postgresql,orm,Mysql,Sql,Sqlite,Postgresql,Orm,关于如何加快SQL数据库的插入速度,有很多问题,例如、、和(我最喜欢的)。许多问题伪装成语言依赖,但问题通常归结为: 哪些常规技术可以加快从[specific language]程序插入[specific DBMS]SQL数据库的速度?插入过程中最大的低效来自两个来源:单个数据事务需要时间,语言和数据库之间的ORM适配器并不总是特别有效 这个答案使用RubyonRails作为示例语言,但是这里展示的技术几乎适用于任何具有底层数据库接口的高级语言 结论(TL;DR) 通过下面列出的任何一种批量插入
哪些常规技术可以加快从[specific language]程序插入[specific DBMS]SQL数据库的速度?插入过程中最大的低效来自两个来源:单个数据事务需要时间,语言和数据库之间的ORM适配器并不总是特别有效 这个答案使用RubyonRails作为示例语言,但是这里展示的技术几乎适用于任何具有底层数据库接口的高级语言 结论(TL;DR) 通过下面列出的任何一种批量插入方法一次插入500条记录,可以使您的速度提高20倍以上。通过调整,这一点可能会变得更高 测试 让我们从内存中123001条记录的数组开始。(这些数据来源于[多伦多市交通数据集]中的“trips.txt”文件。) 基线:一次插入一个 在Ruby On Rails中,您可以执行以下操作:
dataset.each {|record| Trip.create!(record) }
这实际上转化为123000个单独的SQL调用,形式如下:
INSERT INTO "trips" (<column_names>) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) [<column name/value pairs>]
(123000 more times...)
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:批量插入版本B
一些DBMS不支持大容量插入版本A(特别是SQLite的旧版本)的语法。以下表单在功能上完全相同,并且受到许多数据库的支持(尽管不完全符合SQL-92):
加速4:特定于DBM的方法
正如作者所指出的,一个人可以
例如,利用特定于供应商的批量装载命令
为MySQL加载数据填充,为PostgreSQL加载复制,或为MySQL加载SQL*加载程序
甲骨文等。每个品牌都有自己的命令或工具,因此没有
供应商中立的方法,但这些方法通常有
数量级性能更好,因此它们不应
忽视了
虽然这些不是通用的技术,但在特定情况下它们会很有用。在下面的测试中,我们没有对其中任何一个进行基准测试
相对加速比
我们在MySQL、PostgreSQL和SQLite中测试了上述各种技术。下面的数字显示了各种方法相对于基线情况的速度。第一个数字是相对用户+系统时间,括号中的数字是相对运行时间
(注意:我选择不显示绝对时间,因为这不是关于哪个数据库最快的讨论——有太多的变量,无法对此做出合理的声明。如果轻推,我将在github上发布这两个代码,您可以运行自己的测试并得出自己的结论。)
MySQL
- 包裹在事务中:1.2x(1.4x)
- 大容量插入版本A:24.3x(19.0x)
- 批量插入版本B:24.3x(17.1x)
- 包裹在事务中:1.2x(1.6x)
- 批量插入版本A:27.2x(16.7x)
- 批量插入版本B:27.2x(13.9x)
- 包裹在事务中:1.6倍(2.4倍)
- 大容量插件版本A:25.8x(24.7x)
- 批量插入版本B:24.1x(34.1x)
插入过程中最大的低效来自两个方面:单个数据事务需要时间,并且语言和数据库之间的ORM适配器并不总是特别有效 这个答案使用RubyonRails作为示例语言,但是这里展示的技术几乎适用于任何具有底层数据库接口的高级语言 结论(TL;DR) 通过下面列出的任何一种批量插入方法一次插入500条记录,可以使您的速度提高20倍以上。通过调整,这一点可能会变得更高 测试 让我们从内存中123001条记录的数组开始。(这些数据来源于[多伦多市交通数据集]中的“trips.txt”文件。) 基线:一次插入一个 在Ruby On Rails中,您可以执行以下操作:
dataset.each {|record| Trip.create!(record) }
这实际上转化为123000个单独的SQL调用,形式如下:
INSERT INTO "trips" (<column_names>) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) [<column name/value pairs>]
(123000 more times...)
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:批量插入版本B
一些DBMS不支持大容量插入版本A(特别是SQLite的旧版本)的语法。以下表单在功能上完全相同,并且受到许多数据库的支持(尽管不完全符合SQL-92):
加速4:特定于DBM的方法
正如作者所指出的,一个人可以
例如,利用特定于供应商的批量装载命令
为MySQL加载数据填充,为PostgreSQL加载复制,或为MySQL加载SQL*加载程序
甲骨文等。每个品牌都有自己的命令或工具,因此没有
供应商中立的方法,但这些方法通常有
数量级性能更好,因此它们不应
忽视了
虽然这些不是通用的技术,但在特定情况下它们会很有用。在下面的测试中,我们没有对其中任何一个进行基准测试
相对加速比
我们在MySQL、PostgreSQL和SQLite中测试了上述各种技术。下面的数字显示了各种方法相对于基线情况的速度。第一个数字是相对用户+系统时间,括号中的数字是相对运行时间
(注意:我选择不显示绝对时间,因为这不是关于哪个数据库最快的讨论——有太多的变量,无法对此做出合理的声明。如果轻推,我将在github上发布这两个代码,您可以运行自己的测试并得出自己的结论。)
MySQL
- 包裹在事务中:1.2x(1.4x)
- 大容量插入版本A:24.3x(19.0x)
- 批量插入版本B:24.3x(17.1x)
- 包裹在事务中:1.2x(1.6x)
- 批量插入版本A:27.2x(16.7x)
- 批量插入版本B:27.2x(13.9x)
- 包裹在事务中:1.6倍(2.4倍)
- 批量插入版本A:25.8x(24.7
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