Ben*_*Ben 18 mysql files optimization performance-tuning
这个问题是从Stack Overflow转发的根据评论中的建议发布的,为重复道歉。
问题 1:随着数据库表的大小变大,我如何调整 MySQL 以提高 LOAD DATA INFILE 调用的速度?
问题 2:使用一组计算机加载不同的 csv 文件,是提高性能还是杀死它?(这是我明天使用加载数据和批量插入的基准测试任务)
我们正在为图像搜索尝试不同的特征检测器和聚类参数组合,因此我们需要能够及时构建大型数据库。
这台机器有 256 gig 的 ram,如果有办法通过分发数据库来改善创建时间,还有另外 2 台具有相同数量的 ram 的机器吗?
表架构看起来像
+---------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+------------------+------+-----+---------+----------------+
| match_index | int(10) unsigned | NO | PRI | NULL | |
| cluster_index | int(10) unsigned | NO | PRI | NULL | |
| id | int(11) | NO | PRI | NULL | auto_increment |
| tfidf | float | NO | | 0 | |
+---------------+------------------+------+-----+---------+----------------+
Run Code Online (Sandbox Code Playgroud)
创建于
CREATE TABLE test
(
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL AUTO_INCREMENT,
tfidf FLOAT NOT NULL DEFAULT 0,
UNIQUE KEY (id),
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
Run Code Online (Sandbox Code Playgroud)
第一步是比较批量插入与从二进制文件加载到空表中。
It took: 0:09:12.394571 to do 4,000 inserts with 5,000 rows per insert
It took: 0:03:11.368320 seconds to load 20,000,000 rows from a csv file
Run Code Online (Sandbox Code Playgroud)
鉴于我从二进制 csv 文件加载数据时的性能差异,首先我使用下面的调用加载了包含 100K、1M、20M、200M 行的二进制文件。
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test;
Run Code Online (Sandbox Code Playgroud)
2 小时后,我终止了 200M 行二进制文件(~3GB csv 文件)的加载。
所以我运行了一个脚本来创建表格,并从二进制文件中插入不同数量的行,然后删除表格,见下图。
从二进制文件中插入 1M 行大约需要 7 秒。接下来,我决定对一次插入 100 万行进行基准测试,以查看在特定数据库大小下是否会出现瓶颈。一旦数据库达到大约 59M 行,平均插入时间下降到大约 5,000/秒
设置全局 key_buffer_size = 4294967296 稍微提高了插入较小二进制文件的速度。下图显示了不同行数的速度
但是对于插入 1M 行,它并没有提高性能。
行:1,000,000 时间:0:04:13.761428 插入/秒:3,940
vs 空数据库
行数:1,000,000 时间:0:00:6.339295 次插入/秒:315,492
使用以下顺序加载数据与仅使用加载数据命令
SET autocommit=0;
SET foreign_key_checks=0;
SET unique_checks=0;
LOAD DATA INFILE '/mnt/imagesearch/tests/eggs.csv' INTO TABLE test_ClusterMatches;
SET foreign_key_checks=1;
SET unique_checks=1;
COMMIT;
Run Code Online (Sandbox Code Playgroud)
因此,就正在生成的数据库大小而言,这看起来很有希望,但其他设置似乎不会影响加载数据 infile 调用的性能。
然后我尝试从不同的机器加载多个文件,但是 load data infile 命令锁定了表,因为文件很大,导致其他机器超时
ERROR 1205 (HY000) at line 1: Lock wait timeout exceeded; try restarting transaction
Run Code Online (Sandbox Code Playgroud)
rows: 10,000,000 seconds rows: 0:01:36.545094 inserts/sec: 103578.541236
rows: 20,000,000 seconds rows: 0:03:14.230782 inserts/sec: 102970.29026
rows: 30,000,000 seconds rows: 0:05:07.792266 inserts/sec: 97468.3359978
rows: 40,000,000 seconds rows: 0:06:53.465898 inserts/sec: 96743.1659866
rows: 50,000,000 seconds rows: 0:08:48.721011 inserts/sec: 94567.8324859
rows: 60,000,000 seconds rows: 0:10:32.888930 inserts/sec: 94803.3646283
Run Code Online (Sandbox Code Playgroud)
建立表
CREATE TABLE test (
match_index INT UNSIGNED NOT NULL,
cluster_index INT UNSIGNED NOT NULL,
id INT NOT NULL ,
tfidf FLOAT NOT NULL DEFAULT 0,
PRIMARY KEY(cluster_index,match_index,id)
)engine=innodb;
Run Code Online (Sandbox Code Playgroud)
用 SQL
LOAD DATA INFILE '/mnt/tests/data.csv' INTO TABLE test FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
Run Code Online (Sandbox Code Playgroud)
随着数据库大小的增长,使用脚本来预先计算索引似乎已经消除了性能损失。
大约快 3 倍,不考虑将内存表移动到基于磁盘的表的成本。
rows: 0 seconds rows: 0:00:26.661321 inserts/sec: 375075.18851
rows: 10000000 time: 0:00:32.765095 inserts/sec: 305202.83857
rows: 20000000 time: 0:00:38.937946 inserts/sec: 256818.888187
rows: 30000000 time: 0:00:35.170084 inserts/sec: 284332.559456
rows: 40000000 time: 0:00:33.371274 inserts/sec: 299658.922222
rows: 50000000 time: 0:00:39.396904 inserts/sec: 253827.051994
rows: 60000000 time: 0:00:37.719409 inserts/sec: 265115.500617
rows: 70000000 time: 0:00:32.993904 inserts/sec: 303086.291334
rows: 80000000 time: 0:00:33.818471 inserts/sec: 295696.396209
rows: 90000000 time: 0:00:33.534934 inserts/sec: 298196.501594
Run Code Online (Sandbox Code Playgroud)
通过将数据加载到基于内存的表中,然后将其分块复制到基于磁盘的表中,通过查询复制 107,356,741 行的开销为 10 分 59.71 秒
insert into test Select * from test2;
Run Code Online (Sandbox Code Playgroud)
这使得加载 100M 行大约需要 15 分钟,这与直接将其插入基于磁盘的表大致相同。
好问题 - 解释得很好。
如何调整 MySQL 以提高 LOAD DATA INFILE 调用的速度?
您已经为密钥缓冲区设置了较高的设置 - 但这足够了吗?我假设这是一个 64 位安装(如果不是,那么您需要做的第一件事就是升级)并且不在 MSNT 上运行。运行一些测试后查看 mysqltuner.pl 的输出。
为了充分利用缓存,您可能会发现对输入数据进行批处理/预排序的好处(“排序”命令的最新版本具有许多用于对大型数据集进行排序的功能)。另外,如果您在 MySQL 之外生成 ID 号,那么它可能会更有效。
将使用一组计算机来加载不同的 csv 文件
假设(再次)您希望输出集表现为单个表,那么您将获得的唯一好处是通过分配排序和生成 id 的工作 - 您不需要更多的数据库。OTOH 使用数据库集群,您将遇到争用问题(除了性能问题之外,您不应该看到这种问题)。
如果您可以对数据进行分片并独立处理生成的数据集,那么是的,您将获得性能优势 - 但这并不能消除调整每个节点的需要。
检查您是否有至少 4 GB 的 sort_buffer_size。
除此之外,性能的限制因素都与磁盘 I/O 有关。有很多方法可以解决这个问题 - 但您可能应该考虑在 SSD 上使用一组镜像的条带数据集以获得最佳性能。
归档时间: |
|
查看次数: |
8991 次 |
最近记录: |