如何提高插入速度?
How can I increase insert speed?
我需要将数据从外部网络服务导入我的 mySQL(5.7) 数据库。
问题是,我需要将数据拆分为 tables。例如,我有 tables
CREATE TABLE a (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100)
);
CREATE TABLE b (
id INT PRIMARY KEY AUTO_INCREMENT,
a_id INT,
name VARCHAR(100)
);
现在我必须将多行插入 table b 中的一行 table a (1:n)
由于在插入之前不知道 table a 的 id,唯一的方法是在 table a 中插入一行,获取最后一个 id,然后将所有连接的条目插入到 table b.
但是,当我逐行插入时,我的数据库非常慢。在tablea中插入大约35000行,在tableb中插入大约120000行,需要1个多小时。如果我在 table a 上批量插入大约 1000 行(仅用于测试而不填充 table b),速度会快得令人难以置信(不到 3 分钟)
我想一定有一个解决方案可以加快我的导入速度。
感谢您的帮助
我假设您正在使用驱动插入的编程语言。您需要能够对这一系列操作进行编程。
首先,您需要使用此序列将一行放入a
,将相关行放入b
。它使用 LAST_INSERT_ID() 来处理 a_id
。这比查询 table 以找到正确的 id 值更快、更可靠。
INSERT INTO a (name) VALUES ('Claus');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'von');
INSERT INTO b (a_id, name) VALUES (@a_id, 'Bönnhoff');
诀窍是在会话变量 @a_id
中捕获 a.id
值,然后将其重新用于每个依赖的 INSERT。 (我把你变成了贵族来说明这一点,抱歉:-)
其次,你应该牢记这一点:INSERT 很便宜,但是transaction COMMITs 很昂贵。那是因为 MySQL(实际上是 InnoDB)直到 COMMIT 才真正更新 tables。除非您显式管理事务,否则 DBMS 使用称为“自动提交”的功能,它会立即提交每个 INSERT(或 UPDATE 或 DELETE)。
交易越少,速度越快。因此,为了提高批量加载性能,您希望将 100 个左右的 INSERT 捆绑到一个事务中。 (确切的数字并不重要。)你可以这样做:
START TRANSACTION; /* start an insertion bundle */
INSERT INTO a (name) VALUES ('Claus');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'von');
INSERT INTO b (a_id, name) VALUES (@a_id, 'Bönnhoff');
INSERT INTO a (name) VALUES ('Oliver');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'Jones');
... more INSERT operations ...
INSERT INTO a (name) VALUES ('Jeff');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'Atwood');
COMMIT; /* commit the bundle */
START TRANSACTION; /* start the next bundle */
INSERT INTO a (name) VALUES ('Joel');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'Spolsky');
... more INSERT operations ...
COMMIT; /* finish the bundle */
(除 LAST_INSERT_ID() 外,所有这些都适用于任何基于 SQL 的 RDBMS。每个 RDBMS 品牌都有自己的处理 ID 的方式。(
我需要将数据从外部网络服务导入我的 mySQL(5.7) 数据库。 问题是,我需要将数据拆分为 tables。例如,我有 tables
CREATE TABLE a (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100)
);
CREATE TABLE b (
id INT PRIMARY KEY AUTO_INCREMENT,
a_id INT,
name VARCHAR(100)
);
现在我必须将多行插入 table b 中的一行 table a (1:n) 由于在插入之前不知道 table a 的 id,唯一的方法是在 table a 中插入一行,获取最后一个 id,然后将所有连接的条目插入到 table b.
但是,当我逐行插入时,我的数据库非常慢。在tablea中插入大约35000行,在tableb中插入大约120000行,需要1个多小时。如果我在 table a 上批量插入大约 1000 行(仅用于测试而不填充 table b),速度会快得令人难以置信(不到 3 分钟)
我想一定有一个解决方案可以加快我的导入速度。
感谢您的帮助
我假设您正在使用驱动插入的编程语言。您需要能够对这一系列操作进行编程。
首先,您需要使用此序列将一行放入a
,将相关行放入b
。它使用 LAST_INSERT_ID() 来处理 a_id
。这比查询 table 以找到正确的 id 值更快、更可靠。
INSERT INTO a (name) VALUES ('Claus');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'von');
INSERT INTO b (a_id, name) VALUES (@a_id, 'Bönnhoff');
诀窍是在会话变量 @a_id
中捕获 a.id
值,然后将其重新用于每个依赖的 INSERT。 (我把你变成了贵族来说明这一点,抱歉:-)
其次,你应该牢记这一点:INSERT 很便宜,但是transaction COMMITs 很昂贵。那是因为 MySQL(实际上是 InnoDB)直到 COMMIT 才真正更新 tables。除非您显式管理事务,否则 DBMS 使用称为“自动提交”的功能,它会立即提交每个 INSERT(或 UPDATE 或 DELETE)。
交易越少,速度越快。因此,为了提高批量加载性能,您希望将 100 个左右的 INSERT 捆绑到一个事务中。 (确切的数字并不重要。)你可以这样做:
START TRANSACTION; /* start an insertion bundle */
INSERT INTO a (name) VALUES ('Claus');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'von');
INSERT INTO b (a_id, name) VALUES (@a_id, 'Bönnhoff');
INSERT INTO a (name) VALUES ('Oliver');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'Jones');
... more INSERT operations ...
INSERT INTO a (name) VALUES ('Jeff');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'Atwood');
COMMIT; /* commit the bundle */
START TRANSACTION; /* start the next bundle */
INSERT INTO a (name) VALUES ('Joel');
SET @a_id = LAST_INSERT_ID();
INSERT INTO b (a_id, name) VALUES (@a_id, 'Spolsky');
... more INSERT operations ...
COMMIT; /* finish the bundle */
(除 LAST_INSERT_ID() 外,所有这些都适用于任何基于 SQL 的 RDBMS。每个 RDBMS 品牌都有自己的处理 ID 的方式。(