使用远程tcp服务器降低H2性能

时间:2015-01-26 23:36:46

标签: database performance h2

我有一个使用单个连接的简单应用程序,流程是这样的:

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秒后结束,但是当我切换到服务器模式时,性能会下降:

  • localhost:110秒
  • 远程服务器(LAN):超过30分钟

每个查询都会检索少量数据

是否有对这种糟糕表现的解释?如何在不重写代码的情况下加速应用程序?

感谢任何帮助

2 个答案:

答案 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版本进行了测试。

  1. 创建一个包含500.000条记录的测试数据库,数据库大小为990 MB
    java -cp h2-1.3.168.jar;. PerfH2 create
  2. 在索引列上选择随机的8.000条记录 在嵌入模式下 - &gt; 1.7秒
    java -cp h2-1.3.168.jar;. PerfH2 embedded
    在服务器(localhost)模式下 - &gt; 2.6秒
    java -cp h2-1.3.168.jar;. PerfH2 server
  3. 如果您遇到问题已经使用服务器模式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]");
        }
    }