准备好的语句是否比大量插入的单个查询慢得多?

问题描述

我要在MysqL表中插入几百万行。我正在使用如下所示的准备好的语句。

创建单个插入字符串(如正下方的字符串)会更快吗?

Is 22 seconds a good time for inserting 500 rows in mysql?开始的单字符串方法

INSERT INTO example
  (example_id,name,value,other_value)
VALUES
  (100,'Name 1','Value 1','Other 1'),(101,'Name 2','Value 2','Other 2'),(102,'Name 3','Value 3','Other 3'),(103,'Name 4','Value 4','Other 4');

我目前正在做什么:

// 
// method to do upload
// 

public static void doUpload(Connection conn) {
    log.info("Deleting existing data...");
    Database.update("truncate table attribute",conn);
    log.info("Doing inserts");
    String sqlString = "insert into attribute values (null,?,?)";
    int max = 1000000;
    PreparedStatement ps = Database.getPreparedStatement(sqlString,conn);
    for (int i = 0; i < max; i++) {
        // add params
        String subjectId = i+"";
        addParam(subjectId,"GENDER",getGender(),ps);
        addParam(subjectId,"AGE",getAge(),"CITY",getCity(),"FAVORITE_COLOR",getColor(),"PET",getPet(),ps);
        if (i % 1000 == 0) {
            log.info("Executing " + i + " of " + max);
            Database.execute(ps);
            log.info("Done with batch update");
            ps = Database.getPreparedStatement(sqlString,conn);
        }
    }
    if (Database.isClosed(ps) == false) {
        Database.execute(ps);
    }
}

// 
// method to add param to the prepared statement
// 

private static void addParam(String subjectId,String name,String val,PreparedStatement ps) {
    ArrayList<String> params;
    params = new ArrayList<String>();
    params.add(subjectId + "");
    params.add(name);
    params.add(val);
    Database.addToBatch(params,ps);
}

// 
// addToBatch
// 

public static void addToBatch(List<String> params,PreparedStatement ps) {
    try {
        for (int i = 0; i < params.size(); i++) {
            ps.setString((i + 1),params.get(i));
        }
        ps.addBatch();
    } catch (Exception exp) {
        throw new RuntimeException(exp);
    }
}

进行这种插入的最快方法是什么?

我目前大约在5秒钟内插入1000行。期望比这好得多是否合理? 我正在本地运行,并且已经将要插入的表上的所有索引删除

解决方法

使用JDBC进行批量插入的最快方法是使用addBatch / executeBatch, 您似乎已经在做。

有关示例代码,请参见

但这只会为您带来如此多的性能。 为了真正提高性能,请在您的JDBC URL中添加rewriteBatchedStatements=true。 您会看到一个明显的进步。

请参见MySQL and JDBC with rewriteBatchedStatements=true

请记住,您在“单字符串方法”中的建议是相似的,但是rewriteBatchedStatements=true也使与数据库的网络通信更加有效。

,

不确定Database.getPreparedStatement在做什么,但是通常不需要在每次执行批处理后重新创建PreparedStatement对象,仍然可以重用它。 您是否尝试过设置更大的批量大小?截至目前,您的批次大小为1000,您是否尝试过使其更大?

,

准备好的语句具有安全性的优点。从理论上讲,准备好的语句为precompiled,并且仍应提供更好的性能。