【问题标题】:how to optimize the insert statement to achive utmost performance如何优化插入语句以实现最佳性能
【发布时间】:2015-08-12 10:43:06
【问题描述】:

我使用JDBC",我写了下面的“insertRecord”方法,它应该被多次调用并将记录插入数据库表中。当我为每 500 条记录运行代码时“批次的大小” 这需要 20 秒,而且速度非常慢,因为该代码应该在不同的 xml 文件上运行 30 次以隔离它们并将一些数据插入到数据库表中。

对于如何优化代码以达到最佳性能有什么建议吗?

CreateTable 方法

public void CreateTable(String tableName) throws SQLException, ClassNotFoundException {

    if (this.isTableExists(tableName)) {
        Log.i(TAG, "CreateTable", "table: ["+tableName+"] already exists.");

        this.connInsert  = this.getConnection();
        this.connInsert.setAutoCommit(true);
        this.psInsert = this.connInsert.prepareStatement("insert into "+this.TABLE_NAME+" ("+this.NODE_ID_COL+", "+this.LAT_COL+", "+this.LNG_COL+", "+this.XML_PATH_COL+") values (?, ?, ?, ?)");

    } else {
        Log.i(TAG, "CreateTable", "table: ["+tableName+"] does not exist, will be created");
        Connection conn = this.getConnection();
        Statement stmt = conn.createStatement();
        stmt.executeUpdate(this.sqlTable);

        stmt.close();
        conn.close();

        this.connInsert  = this.getConnection();
        this.connInsert.setAutoCommit(true);
        this.psInsert = this.connInsert.prepareStatement("insert into "+this.TABLE_NAME+" ("+this.NODE_ID_COL+", "+this.LAT_COL+", "+this.LNG_COL+", "+this.XML_PATH_COL+") values (?, ?, ?, ?)");

    }
}

插入记录方法

public void insertRecord(Record rec) throws SQLException, ClassNotFoundException {

    if (this.isTableExists(this.TABLE_NAME)) {

        this.psInsert.setString(1, rec.getNodeID());
        this.psInsert.setString(2, rec.getLat());
        this.psInsert.setString(3, rec.getLng());
        this.psInsert.setString(4, rec.getPath());

        this.psInsert.addBatch();

        if (++this.batchCnt == SysConsts.BATCH_SIZE) {
            this.psInsert.executeBatch();
            this.batchCnt = 0;

            Log.d(TAG, "insertRecord", SysConsts.BATCH_SIZE+" records inserted.");
        }

    } else {
        Log.e(TAG, "insertRecord", "table: ["+this.TABLE_NAME+"] does not exist");
    }

}

fluch 方法,用于刷新批处理中的剩余记录

//this method should be called in the end of the code to flush the remaining records in the batch

public void flush() throws SQLException {
    this.psInsert.executeBatch();

    this.psInsert.close();
    this.connInsert.close();

    Log.d(TAG, "insertRecord", "the rest of the records flushed into data base table.");
}

【问题讨论】:

    标签: java sqlite jdbc


    【解决方案1】:

    以下是典型的答案:

    • 使用与您相同的存储过程(或某些准备语句)
    • 将所有插入包装在一个事务中(非常重要,因为它会减少 io 写入量)
    • 更改连接类型(如 sqlite 中的日志)
    • 使用 blob(非常罕见)

    【讨论】:

    • 我认为,在我发布的代码中,我实现了你提到的第二点和最后一点,但关于你提到的第一点和第三点,如果你提供示例,我将不胜感激
    • 我认为特别是因为this.connInsert.setAutoCommit(true);,您没有使用单个事务。尝试将其设置为 false
    • 我在做JDB和sqlite,sqlite中没有存储过程。有什么建议吗? MongoDB?
    • @rmaik,我认为 prepareStatement 无论如何都会与 StoredProcedure 相提并论,除了它的创建(一次)
    【解决方案2】:

    使用stored procedures。它们比正常的 SQL 执行要快得多。

    过程的查询计划通常被缓存,允许您重复使用它 一次又一次,无需重新准备。

    由于存储过程是一次性解析、编译的,并且 可执行文件缓存在数据库中。因此,如果相同的查询是 重复多次然后数据库直接执行可执行文件 因此时间保存在 Parse、Compile 等中。如果查询是 经常使用。如果查询不经常使用,那么它可能不会 很好,因为存储缓存的可执行文件需要空间,为什么要放 Load 不必要地在数据库上。

    【讨论】:

    • 你能提供一个例子如何将上面发布的插入方法转换为存储过程吗?
    猜你喜欢
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 2011-01-04
    • 2011-02-17
    相关资源
    最近更新 更多