Почему SQLite так медленно работает с JDBC? - PullRequest
0 голосов
/ 11 мая 2018

A прочитал много вещей, как здесь: SQLite запросы гораздо медленнее, используя JDBC, чем в плагине Firefox SqliteManager

Но я понятия не имею, в чем проблема.Дело в том, что у меня есть база данных SQLite (с планшета Android) и не слишком большая таблица (в ней ~ 50 000 строк). Если я запускаю «select * from table », например, в Sqlite Managerзанимает 0,11 с, правильно.

Но ... если я делаю это в программе на Java (с SQLite JDBC), это занимает 20 минут !!!Не шучу.

Кто-то (где-то) сказал, что это зависит от версий.Но мой вопрос: как?

Потому что эта команда: «SELECT sqlite_version ()» дает разные результаты для одного и того же файла .db в каждом случае:

  • в очень старом менеджере sqliteон дает 3.6.19
  • в Sqlite Studio 3.15
  • , а с новейшим .exe от sqlite.org - 3.23.1 Так что это не связано с базой данных, я думаю, что это версияиз sqlite3.exe.

Я могу менять драйвер JDBC весь день (я делал это несколько раз), но как узнать, какой мне нужен?

Кто-нибудьс какой мыслью?Я полностью застрял с этим.

РЕДАКТИРОВАТЬ: Хорошо, поэтому JAR-баночки отсюда: https://bitbucket.org/xerial/sqlite-jdbc/downloads/

И мой код действительно прост, сначала я просто хотел измерить скорость.

        Class.forName("org.sqlite.JDBC");
        Connection c1 = DriverManager.getConnection("jdbc:sqlite:" + "c:\\database.db");

        PreparedStatement stmt1 = c1.prepareStatement("select * from table1;");
        ResultSet rs = stmt1.executeQuery();
        String script = "insert into table1 values ";
        while (rs.next()) {
            script += "(";
            script += rs.getInt(1) + ", '" + rs.getString(2) + "', '" + rs.getString(3) + "'";
            script += "),";
        }
        stmt1.close();
        c1.close();

И строка executeQuery () занимает 20 минут.

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Вы создаете String с 50 тыс. Строк, это означает, что вы создаете 50 тыс. * 5 String (каждая конкатенация создает новый String экземпляр. Это то, что убивает вашу производительность.

while (rs.next()) {
    script += "(";
    script += rs.getInt(1) + ", '" + rs.getString(2) + "', '" + rs.getString(3) + "'";
    script += "),";
}

Я заметил, что вы не оправдываете String script, поэтому, если вы просто хотите создать String, используйте StringBuilder

StringBuilder script = new StringBuilder("insert into table1 values ");
    while (rs.next()) {
        script.append("(")
              .append(rs.getInt(1)).append(", '")
              .append(rs.getString(2)).append("', '")
              .append(rs.getString(3)).append("'")
          .append("),");
    }

script.setLength(script.length() - 1); //to remove the last comma.

String query = script.toString();

StringBuilder предотвращает огромное количество экземпляров String, созданных даром.

Если вы хотите вставить эти значения после этого, используйте PreparedStatement напрямую вместо построения запроса:

PreparedStatement psInsert = c1.prepareStatement("insert into table1 values (?,?,?)");
while (rs.next()) {
    psInsert.setInt(1, rs.getInt(1));
    psInsert.setString(2, rs.getString(2));
    psInsert.setString(2,rs.getString(3));

    psInsert.execute();
}

Тогда, если вы хотите улучшить это, используйте пакетную систему для отправки небольшого блока вставки. Использование Statement.addBatch() и Statement.executeBatch()

 while (rs.next()) {
    psInsert.setInt(1, rs.getInt(1));
    psInsert.setString(2, rs.getString(2));
    psInsert.setString(2,rs.getString(3));

    psInsert.addBatch();
    if(batchSize++ > 100){ //Execute every 100 rows
        psInsert.executeBatch();
        batchSize = 0;
    }
}

if(batchSize > 0){ //execute the remainings data
      psInsert.executeBatch();
}

StringBuilder Benchmark

Не официальный, просто продолжительность простого исполнения

LocalTime start = LocalTime.now();
StringBuilder sb = new StringBuilder("Foo;");
for(int i = 0; i < 50_000; i++){
    sb.append("Row").append(i).append(";\n");
}
System.out.println(Duration.between(start, LocalTime.now()).toNanos());
String s = sb.toString();
System.out.println(s.substring(0, 50));

Это занимает 15 наносекунд

LocalTime start = LocalTime.now();
String s = "Foo;";
for(int i = 0; i < 50_000; i++){
    s += "Row" + i + ";\n";
}
System.out.println(Duration.between(start, LocalTime.now()).toMillis());
System.out.println(s.substring(0, 50));

Это занимает> 6 секунд

0 голосов
/ 11 мая 2018

В успешном приложении мы используем sqlite в качестве базы данных.В нашем приложении мы также используем JPA и определяем базу данных как постоянную единицу в каталоге ресурсов Java:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="jpa" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:/ourdata/mySqliteDB.db" />
             <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
             <property name="eclipselink.logging.level" value="SEVERE"/>
             <property name="eclipselink.jdbc.cache-statements" value="true"/>
             <property name="eclipselink.weaving" value="false"/>
             <property name="eclipselink.weaving.fetch-groups" value="false"/>
             <property name="showSql" value="false"/>
        </properties>
    </persistence-unit>
</persistence>

У нас нет проблем с затягиванием времени при использовании sqlite.

При доступе к большим таблицам базы данных общеизвестно, что для каждого столбца, используемого в sql-запросе, необходимо определить индекс, чтобы обеспечить быстрое время ответа на запрос.Это также относится и к JPA (обычно это запрос «findall»).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...