You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sqlx向MySQL插入记录时在特定场景下速度骤降

解决sqlx事务内批量插入1000条数据过慢的问题

问题场景

使用依赖:

sqlx = { version = "0.6.2", features = ["runtime-tokio-native-tls", "mysql"] }

在release模式下,针对关闭AUTO_COMMIT的本地MySQL 8.0.31服务器执行以下代码:

let mut tx = pool.begin().await?;
for i in 0..1_000 {
    let q = &format!("INSERT INTO tbl_abc(some_col) VALUES ({i})");
    sqlx::query(q).execute(&mut tx).await?;
}
tx.commit().await?;

出现以下现象:

  • 插入1000条记录耗时40秒以上(单条约40ms)
  • 插入50-100条时速度正常(单条约0.12ms)
  • 调整连接池大小无明显改善

问题根源

核心原因是单条语句循环执行的网络交互开销累积:即便在同一个事务内,每条INSERT语句都要经历「客户端发请求→服务器处理→返回响应」的完整流程。小批量时总开销不明显,1000条时往返延迟的总和被放大,导致总耗时剧增。

另外,用format!拼接SQL存在SQL注入风险,且sqlx无法预编译动态生成的语句,每次执行都需要服务器重新解析SQL,额外增加了处理耗时。

优化方案

1. 使用MySQL批量插入语法(快速见效)

利用MySQL的INSERT ... VALUES (...), (...), ...语法,将多条记录合并为单条SQL执行,大幅减少网络往返次数:

let mut tx = pool.begin().await?;

// 构造批量插入SQL
let values = (0..1_000)
    .map(|i| format!("({})", i))
    .collect::<Vec<_>>()
    .join(",");
let q = format!("INSERT INTO tbl_abc(some_col) VALUES {values}");
sqlx::query(&q).execute(&mut tx).await?;

tx.commit().await?;

如果插入数据包含用户输入(需防范SQL注入),改用参数化批量插入:

let mut tx = pool.begin().await?;

// 生成参数占位符
let placeholders = (0..1_000)
    .map(|_| "(?)")
    .collect::<Vec<_>>()
    .join(",");
let q = format!("INSERT INTO tbl_abc(some_col) VALUES {placeholders}");

// 收集所有参数并执行
let params: Vec<i32> = (0..1_000).collect();
sqlx::query(&q)
    .bind_all(params)
    .execute(&mut tx)
    .await?;

tx.commit().await?;

2. 使用sqlx QueryBuilder(安全便捷的参数化批量插入)

sqlx提供QueryBuilder工具,简化参数化批量插入的代码,无需手动拼接占位符:

use sqlx::mysql::MySqlQueryBuilder;

let mut tx = pool.begin().await?;

let mut builder = MySqlQueryBuilder::new("INSERT INTO tbl_abc(some_col) VALUES ");
let mut separated = builder.separated(",");

for i in 0..1_000 {
    separated.push_bind(i);
}

builder.build().execute(&mut tx).await?;

tx.commit().await?;

3. 调整MySQL配置(辅助优化)

若批量插入后仍有性能瓶颈,可检查并调整以下MySQL配置:

  • 增大innodb_buffer_pool_size,让更多数据在内存中处理
  • 调整innodb_log_file_size,减少日志刷盘频率
  • 根据业务需求设置innodb_flush_log_at_trx_commit:1(事务安全)或2(性能优先,适合非核心数据)

内容的提问来源于stack exchange,提问作者at54321

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 09:05:19