我知道你可以一次插入多行,有没有办法在MySQL中一次更新多行(如在一个查询中)?
编辑:例如我有以下内容
Name id Col1 Col2
Row1 1 6 1
Row2 2 2 3
Row3 3 9 5
Row4 4 16 8
Run Code Online (Sandbox Code Playgroud)
我想将以下所有更新组合到一个查询中
UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
Run Code Online (Sandbox Code Playgroud) 我正在尝试找到更快的批量插入方法.
我试图用jdbcTemplate.update(String sql)插入几个批处理,其中sql是由StringBuilder 构建的,如下所示:
INSERT INTO TABLE(x, y, i) VALUES(1,2,3), (1,2,3), ... , (1,2,3)
Run Code Online (Sandbox Code Playgroud)
批量大小正好是1000.我插入了近100批.我使用StopWatch检查了时间并找出了插入时间:
min[38ms], avg[50ms], max[190ms] per batch
Run Code Online (Sandbox Code Playgroud)
我很高兴,但我想让我的代码变得更好.
之后,我尝试使用jdbcTemplate.batchUpdate,如:
jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
// ...
}
@Override
public int getBatchSize() {
return 1000;
}
});
Run Code Online (Sandbox Code Playgroud)
sql的样子
INSERT INTO TABLE(x, y, i) VALUES(1,2,3);
Run Code Online (Sandbox Code Playgroud)
我很失望!jdbcTemplate以分开的方式执行1000行批处理的每个插入.我在mysql_log上找到了,发现有一千个插入.我使用StopWatch检查了时间并找出了插入时间:
min [900ms],avg [1100ms],每批最大[2000ms]
那么,任何人都可以向我解释一下,为什么jdbcTemplate在这个方法中做了单独的插入?为什么方法的名称是batchUpdate?或者可能是我以错误的方式使用这种方法?
MySQL JDBC Driver将这两个属性定义为:
useServerPrepStmts - 如果服务器支持,请使用服务器端预处理语句?
cachePrepStmts - 驱动程序是否应该缓存客户端预处理语句的PreparedStatements的解析阶段,"检查"服务器端准备和服务器端预处理语句本身的适用性?
客户端准备好的语句是否可以重用PreparedStatements对象?
如果useServerPrepStmts启用了,那么究竟正在缓存什么,因为MySQL还没有执行计划缓存?
当jdbcTemplate.batchUpdate(...)正在运行时,我可以看到DB行数逐渐增加(通过count(*)在表中运行),最初是2k然后是3k并且直到10k.2k和3k不是确切的数字有时我得到235然后4567.
我期待一次性提交10 k行(批量大小).根据我的理解,如果最初,我得到行计数0然后下一行计数应该是10k.我不希望逐个插入性能原因,这就是为什么使用批量更新功能,似乎它也不会一次性全部提交.
我想将数据(10k行)仅发送到DB服务器一次,用于我的批量大小.为此,我应该在配置中指定什么?
下面是我编写jdbcTemplate批量更新批量大小为10k的方式.
public void insertRows(...) {
...
jdbcTemplate.batchUpdate(query, new BatchPreparedStatementSetter(){
@Override public void
setValues(PreparedStatement ps, int i) throws SQLException {
...
}
@Override public int getBatchSize() {
if(data == null){
return 0;
}
return data.size();
}
});
}
Run Code Online (Sandbox Code Playgroud)
编辑:将@Transactional添加到isertRows方法仍然可以看到相同的行为.使用Transnational它会在10k行之后提交,但是当我看到count使用UR时(从mytable中选择count(*)与ur)它会显示逐渐更新的数据(2k 4k,直到10k).这意味着数据以块的形式进入服务器(可能是一个再见).我如何一次性发送所有内容.这个问题表明它是使用mysql中的rewriteBatchedStatements实现的,我们在DB2中也有类似的东西.
我正在使用DataSource实现com.ibm.db2.jcc.DB2BaseDataSource
我需要从Spark一个DataFrame写入大约100万行到MySQL但是插入太慢了.我怎样才能改进它?
代码如下:
df = sqlContext.createDataFrame(rdd, schema)
df.write.jdbc(url='xx', table='xx', mode='overwrite')
Run Code Online (Sandbox Code Playgroud) 这是一种加快批量插入性能的方法.可以rewriteBatchedStatements以编程方式设置,而不是通过网址设置?
我需要使用JDBC将大量插入(即两位数百万)插入Oracle-DB.为此,我使用类似下面的类,灵感来自使用JDBC进行批量INSERTS的高效方法:
public class Inserter {
private final int batchSize;
private final Connection con; // with .setAutoCommit(false)
private final PreparedStatement ps;
private int currentSize = 0;
public Inserter(Connection con, PreparedStatement ps, int batchSize) {
this.con = con;
this.ps = ps;
this.batchSize = batchSize;
}
public void addInsert(Object[] vals) throws SQLException {
ps.clearParameters(); // should be redundant, but better safe than sorry
for (int i = 0; i < val.length; i++) {
this.ps.setObject(i + 1, vals[i]);
}
ps.addBatch(); …Run Code Online (Sandbox Code Playgroud) 所以我有一个软件,它基本上从我的 MySQL 数据库下载 1.5K 游戏服务器地址。然后它会对所有玩家执行 ping 操作,然后将在线玩家等信息上传回数据库。该过程如下所示:
到目前为止,我已经能够解决下载服务器主机名并对它们执行 ping 操作的部分,但更新服务器时会出现问题。
为了更新,我考虑使用 for 循环来构造一个由许多更新语句组成的大字符串并立即执行它,但这很容易出现 sql 注入。因此,理想情况下,人们会希望使用准备好的语句。
我使用的 SQL 更新语句是:
UPDATE serverlist SET `onlineplayers` = '3', maxplayers = '10',
name = 'A game server' WHERE `ip` = 'xxx.xxx.xxx.xxx' AND `port` = 1234;
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:
如何使用参数化查询执行所有 1.5K 更新语句?
java ×5
mysql ×5
jdbc ×4
jdbctemplate ×2
sql-update ×2
apache-spark ×1
caching ×1
database ×1
db2-9.7 ×1
oracle ×1
pyspark ×1
spring ×1
spring-batch ×1
spring-jdbc ×1
sql ×1