这里有一个问题,如何正确配置mysql(myisam)以便快速执行批量插入(加载数据infile)。
要导入6个Gb文本文件,15个行,16个列(一些int,一些varchar(255),一个varchar(40),一个char(1)一些日期时间,一个中间文本)。
相对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个数据的数据被快速导入(基于table.myd增加的大小 - 5-8 mb / s),但超过3020 Mb限制的uppon导入速度大大降低 - 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
的变量,不是吗?),所有批量导入都是成功的。所以,我很好奇,如何让mysql立即将所有Key_blocks_used
数据放入磁盘,并释放Key_blocks_used
?.我知道它可能正在进行一些即时排序,但我仍然认为应该可以进行一些缓存的RAM磁盘同步,以便成功管理索引,即使它们并非全部适合内存缓存。所以我的问题是“如何配置mysql,以便批量插入可以避免在(几乎)每个索引上写入磁盘,即使所有索引都不适合缓存?”最后也不是最少 - delay_key_write对于给定的表,设置为1,但与禁用时相比,它没有添加任何加速。
提前感谢任何想法,想法,解释和RTM! (:
还有一个小问题 - 在Key_blocks_unused
变为0之前,我将如何计算多少varchar(40)索引适合缓存?
P.S。使用$myisamchk --keys-used=0 -rq /path/to/db/tbl_name
禁用索引,然后使用$myisamchk -rq /path/to/db/tbl_name
重新启用它们,如Mysql docs中所述,这是一种已知的解决方案,只有在批量插入空表时才有效。如果表中已有某些数据,则必须进行索引唯一性检查,因此禁用索引不是解决方案。
答案 0 :(得分:5)
当您使用“加载数据infile”导入数据时,我认为mysql逐个执行插入,并且每次插入时,它都会尝试更新索引文件.MYI,这可能会减慢导入,因为它消耗了bot每个插入的I / O和CPU资源。
您可以做的是将4个文件添加到导入文件中以禁用表的键并在insert语句的末尾启用它,您应该看到差异。
LOCK TABLES tableName WRITE;
ALTER TABLE tableName DISABLE KEYS;
----
your insert statement from go here..
----
ALTER TABLE tableName ENABLE KEYS
UNLOCK TABLES;
如果您不想编辑数据文件,请尝试使用mysqldump获取正确的转储文件,并且不应该使用导入数据来解决这个问题。
##Dump the database
mysqldump databaseName > database.sql
##Import the database
mysql databaseName < database.sql
希望这有帮助!
答案 1 :(得分:0)
我不确定您提及的key_buffer
是否与key_buffer_size
相同。
我遇到过类似的问题。通过将key_buffer_size
值提升到1GB之类的问题来解决我的问题。查看我的问题here。