我有一个 Java 程序,需要迭代
HashMap
来获取参数,然后用于查询 MySQL 数据库。
代码如下:
Iterator<Entry<String, Double>>it = ws.entrySet().iterator();
Connection con = null;
while(it.hasNext())
{
Entry<String, Double>pairs = it.next();
PreparedStatement ps = con.prepareStatement("select doc_freq from lookup where word=?");
ps.setString(1, pairs.getKey());
ResultSet rs = ps.executeQuery();
}
每次循环迭代(大约 500 次)重复访问数据库的过程正在减慢我的应用程序的速度。
有什么办法可以一次性发送所有这些参数,这样我就只能访问数据库一次吗?
考虑到 ws 是一个地图,您可以这样进行单个查询:
Connection con = getConnection();
Set<String> ks = ws.keySet();
if (ks.size() > 0) {
StringBuilder inStatement = new StringBuilder("?");
for (int i = 1; i < ks.size(); i++) {
inStatement.append(", ?");
}
PreparedStatement ps = con.prepareStatement("select doc_freq from lookup where word in (" + inStatement.toString() + ")");
int k = 1;
for (String key : keySet) {
ps.setString(k++, key);
}
ResultSet rs = ps.executeQuery();
}
从问题中不清楚为什么它很慢,但一个常见的问题是每笔交易的开销。
您可以将 innodb_flush_log_at_trx_commit 设置为 0 或 2,一切都会进行得更快。但请注意,默认值 1 是唯一符合 ACID 的设置。对于大多数设置来说,2 是一个非常好的值。
set global innodb_flush_log_at_trx_commit = 2;
准备一次语句,然后迭代并为其设置参数,然后执行。这是来自javadoc
可以预编译带或不带 IN 参数的 SQL 语句 存储在
对象中。然后可以使用该对象 有效地多次执行该语句。 此方法针对处理参数 SQL 语句进行了优化 受益于预编译。如果驱动支持预编译...PreparedStatement
Iterator<Entry<String, Double>>it = ws.entrySet().iterator();
Connection con = getConnection();
PreparedStatement ps = con.prepareStatement("select doc_freq from lookup where word=?");
while(it.hasNext())
{
Entry<String, Double>pairs = it.next();
ps.setString(1, pairs.getKey());
ResultSet rs = ps.executeQuery();
}
当查询被编译到数据库时,它可以更快地逐一执行和检索结果,这与执行具有多个参数的一个查询相同。性能是平等的。
但是如果你准备好,编译相同的 SQL 查询多种类型,数据库将在每次编译查询时创建执行计划,这是时间上的进攻。
这就是为什么这种技术在文档中被称为高效的原因。该术语也称为解释计划,它是由数据库创建的,以更好地优化查询。