5

这里有一个关于如何正确配置 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 文档中所述,这是一种已知的解决方案,该解决方案有效,但仅在批量插入空表时才有效。当表中已经有一些数据时,索引唯一性检查是必要的,因此禁用索引不是解决方案。

4

2 回答 2

5

当您使用“加载数据 infile”导入数据时,我认为 mysql 会一个一个地执行插入,并且每次插入时,它都会尝试更新索引文件 .MYI,这可能会减慢您的导入速度,因为它会消耗机器人 I/O和每个单独插入的 CPU 资源。

您可以做的是在导入文件中添加 4 个文件以禁用表的键并在插入语句的末尾启用它,您应该会看到不同之处。

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

希望这可以帮助!

于 2009-12-21T13:42:34.937 回答
0

我不确定key_buffer您提到的是否与key_buffer_size.

我遇到过类似的问题。我的问题通过将key_buffer_size值提高到 1GB 来解决。在这里检查我的问题。

于 2009-12-21T16:42:26.150 回答