MySql批处理插入-Win​​dows 10任务管理器上的磁盘使用率为100%

时间:2018-07-09 12:06:38

标签: mysql performance

我正在尝试使用MySQL Batch Prepared Statement插入多行。

我正在本地计算机上进行测试:装有MySQL Server 8.0和Eclipse Photon的Windows 10。

代码开始批量处理时,我的笔记本电脑性能下降。通过查看TaskManager,我发现磁盘使用率达到了100%。

如果我停止在Eclipse上运行,则磁盘使用率将正常化,并且性能问题将消失。总是在我尝试运行我的代码时发生。

我不确定问题是我的代码还是笔记本电脑,因为在打开笔记本电脑,使用mysql启动Windows时,我的发行是相同的。我需要等待几分钟,直到磁盘使用率恢复正常并开始使用笔记本电脑。

private static final String CONNECTION_STRING = "jdbc:mysql://localhost/parser?user=root&password=root&useTimezone=true&serverTimezone=UTC";

MySQLAccess(boolean debug) throws ClassNotFoundException, SQLException{
    Class.forName("com.mysql.cj.jdbc.Driver");
    connect = DriverManager
            .getConnection(CONNECTION_STRING);

    isDebug = debug;
}

private void insertLogTable(List<Map<String, Object>> logList) throws SQLException{
    String sql = "INSERT INTO log (date, ip, request, status, userAgent) VALUES (?, ?, ?, ?, ?)";

    PreparedStatement ps = connect.prepareStatement(sql);

    int i = 0;
    for (Map<String, Object> log : logList) {

        ps.setString(1, getMySQLDateString((Date)log.get("date")));
        ps.setString(2, (String)log.get("ip"));
        ps.setString(3, (String)log.get("request"));
        ps.setString(4, (String)log.get("status"));
        ps.setString(5, (String)log.get("userAgent"));

        ps.addBatch();
        i++;

        if (i % 1000 == 0 || i == logList.size()) {
            ps.executeBatch(); // Execute every 1000 items.
            debug(getMySQLDateString((Date)log.get("date")));
        }
    }

    ps.close();
}

public void close() {
    try {
        if (connect != null) {
            connect.close();
        }
    } catch (Exception e) {

    }
}

编辑:

我运行了“ SELECT @@ innodb_buffer_pool_size”,并得到了“ 8388608”。

我的笔记本电脑有8GB的内存。

CREATE TABLE `log` (
  `date` datetime NOT NULL,
  `ip` varchar(15) NOT NULL,
  `request` varchar(20) NOT NULL,
  `status` varchar(3) NOT NULL,
  `userAgent` varchar(256) NOT NULL,
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `logcol` varchar(45) DEFAULT NULL,
  `logcol1` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `ip_index` (`ip`),
  KEY `date_index` (`date`)
) ENGINE=InnoDB AUTO_INCREMENT=915169 DEFAULT CHARSET=utf8mb4     COLLATE=utf8mb4_0900_ai_ci;

已解决:我已按照问题How to improve performance with executeBatch?

解决了此问题

1 个答案:

答案 0 :(得分:0)

my.cnf中更改为

innodb_buffer_pool_size = 4G

适用于您的8GB计算机。然后重启mysql。

由于RAM中缺少缓存,您当前拥有的8M微小设置会导致大量的I / O。

(如果4G对于其他正在运行的应用来说太大了,请选择其他一些数字,但尝试至少300M。)

我很惊讶Win 10仅能在8G中运行。

令我惊讶的是8.0版最初只有8M。您是否从很久以前继承了该设置(默认设置为8M)?我认为5.5版在2010年将默认值提高到了128M!

更多分析:

ip上的索引可能占用40MB左右。而且,我认为IP地址是随机出现的吗?每次插入新行时,ip的索引都会更新。即,40MB的一个块(大小为16KB)被提取,修改并存储回磁盘。假设随机访问为40MB:8MB,那么80%的提取,修改,写入操作需要命中磁盘。也就是说,对于每1000个行,有800 * 2个磁盘命中仅用于ip索引。另外,“顺序”写入的数据和其他索引的命中数(较小)。我估计还会有20 * 1的磁盘命中。

那只是一个粗略的计算。但是它指出,如果您的buffer_pool大于40MB(假设至少有100MB,考虑到我没有提到的各种因素),那么实际上所有I / O都将消失。一切都将保留在缓存中,因此不需要“提取”。而且“写入”可以延迟,而不必重新执行。