我有一个使用单个连接的简单应用程序,流程是这样的:
SELECT QUERY
CONNECTION CLOSE
for(..) //thousands of iterations
{
SIMPLE SELECT QUERY
}
BUSINESS LOGIC
CONNECTION CLOSE
for(..) //thousands of iterations
{
SIMPLE SELECT QUERY
}
BUSINESS LOGIC
CONNECTION CLOSE
当我使用嵌入式连接模式时,应用程序在大约20秒后结束,但是当我切换到服务器模式时,性能会下降:
每个查询都会检索少量数据。
是否有对这种糟糕表现的解释?如何在不重写代码的情况下加速应用程序?
感谢任何帮助
答案 0 :(得分:2)
比较你的问题,如获取一杯咖啡。
如果你在桌子/工作台上访问你的咖啡,它就像内存访问你的数据库(H2嵌入式) 它需要大约几秒钟(咖啡)和微秒(嵌入h2)
如果您需要去厨房取一杯咖啡,它将带您从椅子到厨房+返回(响应)的旅行时间。 厨房具有可比性,如TCP访问或文件访问本地数据库。 它需要你几分钟(咖啡)和一位数毫秒(h2 tcp localhost或本地文件)
如果你需要去外面的咖啡店买一杯咖啡,你需要至少15分钟才能得到一杯咖啡(和远程机器上的h2 tcp中的年龄(至少2位数))< / p>
现在问题是,你想去coffeshop多少次? 如果我给你coffeshop超过1000次迭代(for循环),你会在第二次或第三次问我,如果我在开玩笑吗?为什么在网络上长途旅行时会打扰IO依赖系统?
因此,在您的情况下,如果您将第二个for循环减少为一个SQL查询,您将在本地获得良好的性能,当然尤其是在远程方式。
我希望我能用咖啡向你解释情况,因为它可以更好地解释问题。
所以要回答最后一个问题,你必须为for循环重写你的“数千次迭代”。
更新1
忘了,如果你的for循环正在编写循环(更新/插入),你可以使用批量查询。如何使用它们取决于您使用的语言。批处理是在操作在数据库上实施之前为数据库提供一堆(例如,数百个)插入/更新。
答案 1 :(得分:1)
我使用您提供的H2版本进行了测试。
java -cp h2-1.3.168.jar;. PerfH2 create
java -cp h2-1.3.168.jar;. PerfH2 embedded
java -cp h2-1.3.168.jar;. PerfH2 server
如果您遇到问题已经使用服务器模式jdbc:h2:tcp://localhost/your_database
,那么您的环境或访问服务器模式的方式似乎是错误的。尝试剥离完成的应用程序并检查问题是否仍然存在。如果您还可以使用精简版重现问题,请发布代码。
找到用于下面测试的代码。
public class PerfH2 {
public static void main(String[] args) throws SQLException {
if (null == args[0]) {
showUsage();
return;
}
long start = System.currentTimeMillis();
switch (args[0]) {
case "create":
createDatabase();
break;
case "embedded":
try (Connection conn = getEmbeddedConnection()) {
execSelects(conn);
}
break;
case "server":
try (Connection conn = getServerConnection()) {
execSelects(conn);
}
break;
default:
showUsage();
}
System.out.printf("duration: %d%n", System.currentTimeMillis() - start);
}
private static Connection getServerConnection() throws SQLException {
return DriverManager.getConnection("jdbc:h2:tcp://localhost/perf_test", "sa", "");
}
private static Connection getEmbeddedConnection() throws SQLException {
return DriverManager.getConnection("jdbc:h2:d:/temp/perf_test", "sa", "");
}
private static void execSelects(final Connection conn) throws SQLException {
Random rand = new Random(1);
String selectSql = "SELECT * FROM TEST_TABLE WHERE ID = ?";
PreparedStatement selectStatement = conn.prepareStatement(selectSql);
int count = 0;
for (int i = 0; i < 8000; i++) {
selectStatement.setInt(1, rand.nextInt(500_000));
ResultSet rs = selectStatement.executeQuery();
while (rs.next()) {
count++;
}
}
System.out.printf("retrieved rows: %d%n", count);
}
private static void createDatabase() throws SQLException {
try (Connection conn = DriverManager.getConnection("jdbc:h2:d:/temp/perf_test", "sa", "")) {
String createTable = "CREATE TABLE TEST_TABLE(ID INT, NAME VARCHAR(1024))";
conn.createStatement().executeUpdate(createTable);
String insertSql = "INSERT INTO TEST_TABLE VALUES(?, ?)";
PreparedStatement insertStmnt = conn.prepareStatement(insertSql);
StringBuilder sb = new StringBuilder(1024);
for (int i = 0; i < 1024 / 10; i++) {
sb.append("[cafebabe]");
}
String value = sb.toString();
int count = 0;
for (int i = 0; i < 50; i++) {
insertStmnt.setInt(1, i);
insertStmnt.setString(2, value);
count += insertStmnt.executeUpdate();
}
System.out.printf("inserted rows: %d%n", count);
conn.commit();
String createIndex = "CREATE INDEX TEST_INDEX ON TEST_TABLE(ID)";
conn.createStatement().executeUpdate(createIndex);
}
}
private static void showUsage() {
System.out.println("usage: PerfH2 [create|embedded|server]");
}
}