这里有一个关于如何正确配置 mysql (myisam) 以便快速执行批量插入(加载数据文件)的问题。
要导入 6 Gb 文本文件,1500 万行,16 列(一些 int,一些 varchar(255),一个 varchar(40),一个 char(1),一些 datetime,一个 mediumtext)。
相对 my.conf 设置:
key_buffer = 800M
max_allowed_packet = 160M
thread_cache_size = 80
myisam_sort_buffer_size = 400M
bulk_insert_buffer_size = 400M
delay_key_write = ON
delayed_insert_limit = 10000
共有三个索引 - 一个主索引(autincrement int)、一个唯一 int 和一个唯一 varchar(40)。
问题是在执行 load data infile 命令后,前 3 gigs 的数据被快速导入(基于 table.myd 的大小增加 - 5-8 mb/s),但是一旦超过 3020 Mb 就会限制导入速度大大减少 - table.myd 的大小正在增长 0.5mb/s。Key_blocks_unused
我注意到,导入过程会在耗尽为零时减慢。这些是mysql> show status like '%key%';
导入开始时的输出:
mysql> show status like '%key%';
+------------------------+---------+
| Variable_name | Value |
+------------------------+---------+
| Com_preload_keys | 0 |
| Com_show_keys | 0 |
| Handler_read_key | 0 |
| Key_blocks_not_flushed | 57664 |
| Key_blocks_unused | 669364 |
| Key_blocks_used | 57672 |
| Key_read_requests | 7865321 |
| Key_reads | 57672 |
| Key_write_requests | 2170158 |
| Key_writes | 4 |
+------------------------+---------+
10 rows in set (0.00 sec)
这就是它在 3020Mb 限制之后的样子,即当下key_blocks_unused
降到零时,这就是批量插入过程变得非常慢的时候:
mysql> show status like '%key%';
+------------------------+-----------+
| Variable_name | Value |
+------------------------+-----------+
| Com_preload_keys | 0 |
| Com_show_keys | 0 |
| Handler_read_key | 0 |
| Key_blocks_not_flushed | 727031 |
| Key_blocks_unused | 0 |
| Key_blocks_used | 727036 |
| Key_read_requests | 171275179 |
| Key_reads | 1163091 |
| Key_write_requests | 41181024 |
| Key_writes | 436095 |
+------------------------+-----------+
10 rows in set (0.00 sec)
问题很清楚,据我了解 - 索引存储在缓存中,但是一旦缓存填满,索引就会被一一写入磁盘,这很慢,因此所有过程都会减慢。如果我禁用基于 varchar(40) 列的唯一索引,因此所有索引都适合Key_blocks_used
(我猜这是直接依赖的变量key_buffer
,不是吗?),所有批量导入都是成功的。所以,我很好奇,如何让 mysqlKey_blocks_used
一次将所有数据放入磁盘,并释放Key_blocks_used
?. 我知道它可能会即时进行一些排序,但是我想它应该可以进行一些缓存的 RAM 磁盘同步,以便成功管理索引,即使它们并不完全适合内存缓存. 所以我的问题是“如何配置 mysql 以便批量插入避免在(几乎)每个索引上写入磁盘,即使所有索引都不适合缓存?" 最后一点 - 对于给定的表,delay_key_write 设置为 1,尽管与禁用时相比,它没有增加任何加速。
提前感谢您的任何想法、想法、解释和 RTM!(:
还有一个小问题——在达到 0 之前,我将如何计算有多少 varchar(40) 索引可以放入缓存Key_blocks_unused
?
PS 禁用索引,$myisamchk --keys-used=0 -rq /path/to/db/tbl_name
然后使用 重新启用它们$myisamchk -rq /path/to/db/tbl_name
,如Mysql 文档中所述,这是一种已知的解决方案,该解决方案有效,但仅在批量插入空表时才有效。当表中已经有一些数据时,索引唯一性检查是必要的,因此禁用索引不是解决方案。