【问题标题】:SQLite - Increase speed of insertionSQLite - 提高插入速度
【发布时间】:2016-07-11 16:44:02
【问题描述】:

我有一种方法可以逐行从文件中读取数据并在逗号之间取值,然后将该值放入 INSERT 查询中。以这种方式保存的文件中的数据:

–,08:10,–,20:20,08:15,08:16,20:26,20:27,08:20,08:21,20:31,20:32,08:30,08:31,20:40,20:41,08:37,08:38,20:46
20:47,08:48,08:50,20:56,20:57,09:00,09:01,21:07,21:08
08:53,–,17:43,09:01,09:03,09:13,09:15,18:02,18:04,–,–,09:19,09:25

这是我的实际代码:

    public void insertTime(SQLiteDatabase database, String table) throws FileNotFoundException {
        BufferedReader br = null;
        String line;

        try {
            int j = 0;
            br = new BufferedReader(new InputStreamReader(context.getAssets().open("time.txt")));
            database.beginTransaction();
            while ((line = br.readLine()) != null) {
                j++;

                String query = "INSERT INTO "+table+""+j+" (arrival, departure) VALUES (?,?)";
                SQLiteStatement statement = database.compileStatement(query);
                // use comma as separator
                String[] time = line.split(",");


                for(int i = 1; i < time.length; i+=2) {

                    statement.bindString(1,time[i-1]);//arrival
                    statement.bindString(2,time[i]);//departure
                    statement.executeInsert();
                    statement.clearBindings();
                }

            }
                database.setTransactionSuccessful();
                database.endTransaction();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

问题是数据插入速度很慢,尽管我使用了SQLiteStatementtransactions。例如,当我插入 69000 行时,大约需要 65,929 秒。

为了提高插入速度,我需要对代码进行哪些更改?

更新

好的,我已经简化了我的代码,我摆脱了 BufferedReader,现在它看起来像这样

public void insertTime(SQLiteDatabase database) throws FileNotFoundException {
        database.beginTransaction();
        int r = 0;
        while (r < 122) {
            r++;
            String query = "INSERT INTO table_1 (arrival, departure) VALUES (?,?)";
            SQLiteStatement statement = database.compileStatement(query);

            for(int i = 1; i < 1100; i++) {
                statement.bindString(1,i+"");//arrival
                statement.bindString(2,i+"");//departure
                statement.executeInsert();
                statement.clearBindings();
            }
        }

        database.setTransactionSuccessful();
        database.endTransaction();
}

但是插入数据还是那么长,超过2分钟。您对如何提高我的第二个示例的速度有任何想法吗?

【问题讨论】:

  • 所有代码都写在 C 上,如果我使用 java,它对我有什么帮助?
  • sqlite 无处不在。在那篇文章中唯一的 C 是如何执行 sqlite 命令。 sql语句在任何介质中都是一样的。
  • 是的,但我几乎都像那里所说的那样做了。我使用了事务和准备好的语句,但速度仍然很慢。

标签: android performance sqlite


【解决方案1】:

Here 是一篇非常详细的帖子,介绍了提高 SQL 插入速度的各种方法。

【讨论】:

    【解决方案2】:

    beginTransaction()setTransactionSuccessful() 移到while 循环之外,它会更快。

    【讨论】:

    • 我确实像你说的那样,但速度还是一样 - 大约 65 秒
    • 你能分享你的改变吗?
    • 嗯。那就难说了。尝试添加一些代码收集 compileStatement() 和 executeInsert() 方法的执行时间,看看瓶颈是什么。一旦知道了,就会有解决办法。
    【解决方案3】:

    while() 循环中的每个项目启动一个新事务。 如果您只有 1 笔交易来完成所有插入操作,它可能会更快一些。

    此外,当您的数据已损坏且String.split 没有为您提供至少 2 项时,您的交易将由于Exception 被抛出而无法正确结束。

    【讨论】:

      【解决方案4】:

      每次在带有索引的表中插入一行时,都必须调整索引。该操作可能成本高昂。索引被保存为 b 树,如果你达到了再平衡点,你肯定会减速。您可以做的一件事是删除您的索引。您也可以删除索引,插入,然后重新创建索引。

      【讨论】:

      • 我也想使 PRAGMA 同步=OFF。但是,我应该把这个命令放在我的代码哪里?
      • @gigs 理论上,连接后的任何地方。但我会在您的交易之前说,如果您继续使用该连接,则在您结束交易后立即再次打开它。
      • 我在事务之前添加了“database.execSQL("PRAGMA synchronous=OFF")”,在事务之后添加了“database.execSQL("PRAGMA synchronous=NORMAL")”。但它给了我一个错误:android.database.sqlite.SQLiteException: Safety level may not be changed inside a transaction (code 1): , while compile: PRAGMA synchronous=OFF
      • @gigs 我没有一起使用过 Android 和 SQLite。尝试在连接后立即移动您的 PRAGMA 作为测试。
      【解决方案5】:

      对于那些使用 JDBC (Java) 的用户:可以肯定的是,您是否首先将 autoCommit 设置为 FALSE

      我猜是这样,因为您使用的是显式事务。

      我通过显式关闭自动提交获得的性能提升超过 1000 倍

      所以:

      Class.forName("org.sqlite.JDBC");
      String urlInput = "jdbc:sqlite:" + databaseFile;
      databaseConnection = DriverManager.getConnection(urlInput);
      databaseConnection.setAutoCommit( false);
      

      还有:

      String sql = "INSERT INTO " + TABLE_NAME + " ( type, bi, ci, fvi, tvi, content_type) VALUES ('V',?,?,?,?,'rtf')";
      PreparedStatement psi = databaseConnection.prepareStatement(sql);
      for( Item item :  items) {
          psi.setInt(1, item.property1);
          // ....
          count = psi.executeUpdate();
      }
      databaseConnection.commit();
      databaseConnection.setAutoCommit( true);
      

      所以,当有人忘记这一点时,这可能会产生巨大的影响。

      【讨论】:

        猜你喜欢
        • 2016-08-14
        • 2021-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多