Java结果集降低了内存数据库中SQLite的速度

Java结果集降低了内存数据库中SQLite的速度,java,sqlite,jdbc,in-memory-database,Java,Sqlite,Jdbc,In Memory Database,我在使用SQLite jdbc驱动程序的Java程序中使用SQLite作为内存中的数据库 我使用的查询相当复杂。然而,它非常快,通常

我在使用SQLite jdbc驱动程序的Java程序中使用SQLite作为内存中的数据库

我使用的查询相当复杂。然而,它非常快,通常<10ms。 不幸的是,即使使用较大的获取大小,事后迭代ResultSet的成本也相当高:

Class.forName("org.sqlite.JDBC");
connection = DriverManager.getConnection("jdbc:sqlite::memory:");

long startTime = System.currentTimeMillis();

Statement stmt = connection.createStatement();
stmt.setFetchSize(1000);
ResultSet rs = stmt.executeQuery(query);

System.out.println("query time " + (System.currentTimeMillis() - startTime));

ResultSetMetaData metaData = rs.getMetaData();
int columns = metaData.getColumnCount();

System.out.println("metadata time " + (System.currentTimeMillis() - startTime));

HashMap<String, String> record = new HashMap<String, String>();
while (rs.next())
{
    System.out.println("get records time " + (System.currentTimeMillis() - startTime));
    for (int i = 1; i <= columns; i++)
    {

        if (metaData.getColumnName(i) != null && rs.getObject(i) != null)
        {
            record.put(metaData.getColumnName(i), rs.getObject(i).toString());
        }
    }
    al.add(record);
}
System.out.println("all time " + (System.currentTimeMillis() - startTime));

我知道,如果fetch的大小太小,ResultSet通常会通过网络到达DB,以移动光标并获取更多数据。但是,在我的例子中,获取大小相当大(1000),数据库在内存中,结果集包含少量条目(for循环的
效率非常低。与其每次重新检索列名,不如执行以下操作:

ResultSetMetaData metaData = rs.getMetaData();
int columns = metaData.getColumnCount();
ArrayList<String> columnNames = new ArrayList<String>();
for (int i = 1; i <= columns; i++) {
    columnNames.add(metaData.getColumnName(i));
}

另外,我不知道为什么每次都要调用
al.add(record);
,而
record
总是指向同一个
HashMap
(反过来,每次通过
while
循环时都会覆盖该HashMap)。请仔细查看您是如何使用
记录的

SQLite是一个嵌入式数据库,不进行任何网络通信;它动态计算结果记录并忽略获取大小


如果查询比较复杂,则搜索和计算下一条记录的速度会相对较慢。

较大的获取大小不一定会提高性能(例如,考虑所需的额外内存分配和垃圾收集),而对于sqlite内存中数据库来说,网络延迟之类的考虑是无关紧要的。我不应该使用“网络”这个术语。我当然知道,内存数据库的上下文中不需要网络。问题确实是查询的复杂性,最重要的是,SQLite的执行计划不好。使用交叉连接(=MySQL中的直接连接)我可以绕过这个问题。谢谢。谢谢你指出这一点。有一些示例代码只是一个快速的破解。实际的问题不是元数据和for循环的访问,而是rs.next()语句。此外,由于复杂的查询和SQLite糟糕的执行计划,这个过程很慢。
ResultSetMetaData metaData = rs.getMetaData();
int columns = metaData.getColumnCount();
ArrayList<String> columnNames = new ArrayList<String>();
for (int i = 1; i <= columns; i++) {
    columnNames.add(metaData.getColumnName(i));
}
for (int i = 0; i < columns; i++)
{
    Object cellObject = rs.getObject(columnNames.get(i));
    if( cellObject != null )
        record.put(cellObject.toString());
}