使用MySQL X DevAPI C++连接器批量插入极慢问题排查
问题原因分析
你的批量插入代码性能低下的核心原因是MySQL X DevAPI的TableInsert是不可变对象:每次调用values()方法时,都会创建一个全新的TableInsert实例,并且会复制之前所有已添加的插入数据。当循环执行MyInsert = MyInsert.values(...)时,循环次数越多,每次需要复制的数据量就越大,时间复杂度直接变成O(n²),这就是values()方法耗时极长的根本原因。
优化方案
方案1:使用参数化批量插入(推荐,安全且高效)
利用executeBatch()方法批量绑定参数,既避免了字符串拼接的SQL注入风险,也避开了TableInsert的不可变对象复制开销:
try { auto stmt = m_DBRegisterConnection->GetSession()->sql( "INSERT INTO MyTable (UniqueID, This, AndThat) VALUES (?, ?, ?)" ); std::vector<mysqlx::Args> batchParams; batchParams.reserve(ToBeInserted); // 预分配内存避免多次扩容 for (int i = 0; i < ToBeInserted; i++) { auto& insertVals = m_MyQueue.getAt(i)->InsertValues; batchParams.emplace_back(insertVals[0], insertVals[1], insertVals[2]); } stmt.executeBatch(batchParams); } catch (std::exception& e) { // 异常处理逻辑 }
方案2:直接构造原生批量INSERT语句
如果场景允许,直接拼接多行VALUES的原生SQL语句执行,性能也会远优于原代码:
try { std::string sql = "INSERT INTO MyTable (UniqueID, This, AndThat) VALUES "; sql.reserve(sql.size() + ToBeInserted * 128); // 预分配足够内存 for (int i = 0; i < ToBeInserted; i++) { if (i != 0) sql += ","; auto& insertVals = m_MyQueue.getAt(i)->InsertValues; // 使用mysqlx::escape避免SQL注入 sql += fmt::format("('{}', '{}', '{}')", mysqlx::escape(insertVals[0]), mysqlx::escape(insertVals[1]), mysqlx::escape(insertVals[2]) ); } m_DBRegisterConnection->GetSession()->sql(sql).execute(); } catch (std::exception& e) { // 异常处理逻辑 }
额外优化建议
- 关闭自动提交:插入前调用
session.startTransaction(),插入完成后执行session.commit(),减少频繁事务提交的开销。 - 调整InnoDB参数:测试环境可临时调整
innodb_flush_log_at_trx_commit=2、增大innodb_log_file_size,减少磁盘IO等待;生产环境根据实际情况调整。 - 提前校验UniqueID:批量插入前先检查待插入数据的UniqueID是否重复,避免数据库层面的唯一索引冲突检查带来的额外耗时。
内容的提问来源于stack exchange,提问作者Bew Games
相关产品推荐
相关产品推荐

