【发布时间】:2022-08-19 22:55:43
【问题描述】:
我正在向 MySQL 数据库中插入大量记录,并且正在尝试实现不错的 INSERT 性能。我正在使用 MySQL 8.0 和 MySQL 连接器 C++ 8.0。
为了确定插入数据的最快方式,我构建了一个小型测试程序,它简单地将 10000 条记录插入到一个表中。如果有帮助,这是表结构:
CREATE TABLE IF NOT EXISTS Parent (
id BIGINT AUTO_INCREMENT NOT NULL PRIMARY KEY,
xxuint1 INTEGER UNSIGNED,
xxuint2 INTEGER UNSIGNED,
xxuint3 INTEGER UNSIGNED,
xxuint4 INTEGER UNSIGNED)
我创建了一个包含值的结构,并创建了一个包含 10,000 个随机数的数组 (tblParent[10000])。这个数组的填充是在插入之前完成的,所以我只能测量插入性能。下面的函数是我的基本插入函数:
void InsertData(sql::Connection* con)
{
sql::PreparedStatement* pstmt = NULL;
try {
std::string sql = \"INSERT INTO Parent(\"
\"xxuint1, xxuint2, xxuint3, xxuint4\"
\") VALUES (?,?,?,?);\";
pstmt = con->prepareStatement(sql);
for (size_t i = 0; i < NUM_PARENTS; ++i) {
pstmt->setUInt(1, tblParent[i].uint1);
pstmt->setUInt(2, tblParent[i].uint2);
pstmt->setUInt(3, tblParent[i].uint3);
pstmt->setUInt(4, tblParent[i].uint4);
pstmt->execute();
}
} catch(sql::SQLException &e) {
std::cout << \"SQLException: \" << e.what() << std::endl;
}
delete pstmt;
}
通常,当插入许多记录时,您可以通过使用多个值列表来获得更好的性能:
INSERT INTO MyTable (col1, col2, col3) VALUES (?, ?, ?), (?, ?, ?), ... number_of_records
而不是一次插入一条记录。 对于每个记录数:
INSERT INTO MyTable (col1, col2, col3) VALUES (?, ?, ?)
我假设上面的代码将在幕后使用多值列表方法,但根据我的性能测量,我不相信它是。
这是我得到的:
具有 10,000 条记录的 InsertData 代码:
~300 条记录/秒。
用 \"START TRANSACTION\" 和 \"COMMIT\" 包围 InsertData:
~8000 条记录/秒
如果我重写插入数据,以便将数组中的数据作为字符串直接插入到 sql 中,例如
std::string sql = \"INSERT INTO Parent(\"
\"xxuint1, xxuint2, xxint3, xxbigint4\"
\") VALUES (\";
for (size_t i = 0; i < NUM_PARENTS; ++i) {
sql += to_string(tblParent[i].uint1) + \", \";
sql += to_string(tblParent[i].uint2) + \", \";
sql += to_string(tblParent[i].uint3) + \", \";
sql += to_string(tblParent[i].uint4) + \"); \";
}
我得到与上述类似的性能。
当我明确开始使用多个值列表时,性能得到了提高。我调整了我的 sql 以包含 \"VALUES (?, ?, ?), (?, ?, ?), ...\",这将性能提高到 ~14,000 条记录/秒。但最好的时间来自将我的数据转换为字符串,并使用多个值列表将该数据直接插入到 sql 中。我这样做的速度高达约 40,000 条记录/秒。
但是,虽然速度还不错,但我不认为将我的数据转换为文本并将其插入到 sql 中是一种理想的方法。如何优化插入速度并仍然使用 pstmt->setUint() 方法?
-
为什么不为此简单地使用 load data infile 语句呢?
-
因为我正在努力的真实场景是记录动态给我的数据。对于上述问题,我试图找到加载数据文件之外的最快插入方法,我意识到如果我有一个文件可以读取,这将是最快的。