MySQL插入性能在大型表上降级

时间:2010-09-09 11:47:01

标签: mysql performance innodb

我正在使用一张有超过250万行的巨大桌子。架构很简单。

CREATE TABLE MyTable (
        id BIGINT PRIMARY KEY AUTO_INCREMENT,
        oid INT NOT NULL,
        long1 BIGINT NOT NULL,
        str1 VARCHAR(30) DEFAULT NULL,
        str2 VARCHAR(30) DEFAULT NULL,
        str2 VARCHAR(200) DEFAULT NULL,
        str4 VARCHAR(50) DEFAULT NULL,
        int1 INT(6) DEFAULT NULL,
        str5 VARCHAR(300) DEFAULT NULL,
        date1 DATE DEFAULT NULL,
        date2 DATE DEFAULT NULL,
        lastUpdated TIMESTAMP NOT NULL,
        hashcode INT NOT NULL,
        active TINYINT(1) DEFAULT 1,
        KEY oid(oid),
        KEY lastUpdated(lastUpdated),
        UNIQUE KEY (hashcode, active),
        KEY (active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 MAX_ROWS=1000000000;

插件的性能显着下降。表中有多达1.5亿行,过去需要5-6秒才能插入10,000行。现在已经上升了2-4倍。 Innodb的ibdata文件已增长到107 GB。 Innodb配置参数如下。

innodb_buffer_pool_size = 36G # Machine has 48G memory
innodb_additional_mem_pool_size = 20M
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_file_size = 50M
innodb_log_buffer_size = 20M
innodb_log_files_in_group=2
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50
innodb_thread_concurrency = 8
innodb_flush_method = O_DIRECT
expire_logs_days = 4

IO等待时间从top开始上升。我已经尝试将flush方法更改为O_DSYNC,但它没有帮助。磁盘由硬件RAID 10设置构成。在早期的单磁盘设置中,IO不是问题。

是否仅对表格进行分区选项?可以将单个100G文件拆分成“较小”的文件有帮助吗?是否有任何需要针对RAID调整的变量?

更新:这是一个测试系统。我可以自由地进行任何更改。

6 个答案:

答案 0 :(得分:15)

你没有说这是测试系统还是生产;我假设它是生产。

很可能你的表格已达到其索引(或整个批次)不再适合内存的大小。

这意味着InnoDB必须在插入期间读取页面(取决于新行的索引值的分布)。阅读页面(随机读取)非常慢,如果可能,需要避免。

分区似乎是最明显的解决方案,但MySQL的分区可能不适合您的用例。

您当然应该考虑所有可能的选项 - 将表格放到实验室的测试服务器上,看看它的行为方式。

您的主键看起来好像可能不需要(您有另一个唯一索引),因此消除它是一个选项。

还要考虑innodb插件和压缩,这将使你的innodb_buffer_pool更进一步。

您确实需要分析您的用例,以确定您是否确实需要保留所有这些数据,以及分区是否是一个明智的解决方案。

对此应用程序进行任何更改可能会为您的用户带来新的性能问题,因此您需要在此处非常小心。如果您找到提高插入性能的方法,则可能会降低搜索性能或其他操作的性能。在发布此类更改之前,您需要对生产级硬件进行全面的性能测试。

答案 1 :(得分:4)

根据我对Innodb的经验,即使你有一个真正优化的磁盘子系统,它也似乎达到了写入密集型系统的极限。我很惊讶你设法达到了100GB。

这就是推特刚刚发布的内容,并意识到需要进行分片 - 请参阅http://github.com/twitter/gizzard

这完全取决于您的使用案例,但您也可以从mysql迁移到cassandra,因为它对写密集型应用程序的效果非常好。(http://cassandra.apache.org)

答案 2 :(得分:1)

正如MarkR上面评论的那样,当索引不再适合缓冲池时,插入性能会变差。 InnoDB有一个随机的IO减少机制(称为插入缓冲区),它可以防止出现这个问题 - 但它不适用于你的UNIQUE索引。必须在每个插入上检查(hashcode,active)上的索引,确保没有插入重复的条目。如果哈希码没有“跟随”主键,则此检查可以是随机IO。

您是否有可能更改架构?

你最好的选择是:

(a)使hashcode成为顺序,或者在批量插入之前按哈希码排序(这本身会有所帮助,因为随机读取将会减少)。

(b)使(哈希码,活动)主键 - 并按排序顺序插入数据。我猜你的应用程序可能是通过哈希码读取的 - 主键查找速度更快。

答案 3 :(得分:1)

您没有提到您的工作负载是什么样的,但如果没有太多的读取或您有足够的主内存,另一个选择是使用针对MySQL的写优化后端,而不是innodb。随着数据集的增长,Tokutek声称插入速度提高了18倍,性能曲线也更平坦。

tokutek.com

http://tokutek.com/downloads/tokudb-performance-brief.pdf

答案 4 :(得分:0)

我将继续关注@ MarkR关于减少索引的评论。您应该关注的另一件事是增加innodb_log_file_size。它会增加崩溃恢复时间,但应该有所帮助。请注意,在重新启动服务器之前,需要删除旧文件。

General InnoDB调整技巧: http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/

您还应该了解LOAD DATA INFILE进行插入操作。它快得多。

答案 5 :(得分:0)

innodb_log_file_size = 50M增加到 innodb_log_file_size = 500M

如果你承受1秒的数据丢失,innodb_flush_log_at_trx_commit应为0。

相关问题