47 mysql myisam performance update mysql-5.6
大多数表使用 MySQL 5.6 和 InnoDB 存储引擎。InnoDB 缓冲池大小为 15 GB,Innodb DB + 索引大约为 10 GB。服务器有 32GB RAM 并运行 Cent OS 7 x64。
我有一张包含大约 1000 万条记录的大表。
我每 24 小时从远程服务器获取更新的转储文件。该文件为 csv 格式。我无法控制那种格式。该文件约为 750 MB。我尝试将数据逐行插入 MyISAM 表,花了 35 分钟。
我只需要从文件中的每行 10-12 中取出 3 个值并在数据库中更新它。
实现这样的目标的最佳方法是什么?
我需要每天都这样做。
目前 Flow 是这样的:
以上操作大约需要30-40 分钟才能完成,在执行此操作时,还有其他更新正在进行中,这给了我
超过锁等待超时;尝试重新启动事务
使用LOAD DATA LOCAL INFILE. 在 MyISAM 中,38.93 sec在 InnoDB 中需要 7 分 5.21 秒。然后我做了:
UPDATE table1 t1, table2 t2
SET
t1.field1 = t2.field1,
t1.field2 = t2.field2,
t1.field3 = t2.field3
WHERE t1.field10 = t2.field10
Query OK, 434914 rows affected (22 hours 14 min 47.55 sec)
Run Code Online (Sandbox Code Playgroud)
与连接查询相同的更新
UPDATE table1 a JOIN table2 b
ON a.field1 = b.field1
SET
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4
(14 hours 56 min 46.85 sec)
Run Code Online (Sandbox Code Playgroud)
评论中问题的澄清:
更新 3:
这里有关于这两个表的更多细节。
CREATE TABLE `content` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`og_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`keywords` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`files_count` smallint(5) unsigned NOT NULL DEFAULT '0',
`more_files` smallint(5) unsigned NOT NULL DEFAULT '0',
`files` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`category` smallint(3) unsigned NOT NULL DEFAULT '600',
`size` bigint(19) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) NOT NULL DEFAULT '0',
`completed` int(11) NOT NULL DEFAULT '0',
`uploaders` int(11) NOT NULL DEFAULT '0',
`creation_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`upload_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`last_updated` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`vote_up` int(11) unsigned NOT NULL DEFAULT '0',
`vote_down` int(11) unsigned NOT NULL DEFAULT '0',
`comments_count` int(11) NOT NULL DEFAULT '0',
`imdb` int(8) unsigned NOT NULL DEFAULT '0',
`video_sample` tinyint(1) NOT NULL DEFAULT '0',
`video_quality` tinyint(2) NOT NULL DEFAULT '0',
`audio_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`subtitle_lang` varchar(127) CHARACTER SET ascii NOT NULL DEFAULT '',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
`uploader` int(11) unsigned NOT NULL DEFAULT '0',
`anonymous` tinyint(1) NOT NULL DEFAULT '0',
`enabled` tinyint(1) unsigned NOT NULL DEFAULT '0',
`tfile_size` int(11) unsigned NOT NULL DEFAULT '0',
`scrape_source` tinyint(1) unsigned NOT NULL DEFAULT '0',
`record_num` int(11) unsigned NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`record_num`),
UNIQUE KEY `hash` (`hash`),
KEY `uploaders` (`uploaders`),
KEY `tfile_size` (`tfile_size`),
KEY `enabled_category_upload_date_verified_` (`enabled`,`category`,`upload_date`,`verified`),
KEY `enabled_upload_date_verified_` (`enabled`,`upload_date`,`verified`),
KEY `enabled_category_verified_` (`enabled`,`category`,`verified`),
KEY `enabled_verified_` (`enabled`,`verified`),
KEY `enabled_uploader_` (`enabled`,`uploader`),
KEY `anonymous_uploader_` (`anonymous`,`uploader`),
KEY `enabled_uploaders_upload_date_` (`enabled`,`uploaders`,`upload_date`),
KEY `enabled_verified_category` (`enabled`,`verified`,`category`),
KEY `verified_enabled_category` (`verified`,`enabled`,`category`)
) ENGINE=InnoDB AUTO_INCREMENT=7551163 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=FIXED
CREATE TABLE `content_csv_dump_temp` (
`hash` char(40) CHARACTER SET ascii NOT NULL DEFAULT '',
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`category_id` int(11) unsigned NOT NULL DEFAULT '0',
`uploaders` int(11) unsigned NOT NULL DEFAULT '0',
`downloaders` int(11) unsigned NOT NULL DEFAULT '0',
`verified` tinyint(1) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`hash`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Run Code Online (Sandbox Code Playgroud)
这是更新查询,它content使用来自的数据更新表content_csv_dump_temp
UPDATE content a JOIN content_csv_dump_temp b
ON a.hash = b.hash
SET
a.uploaders = b.uploaders,
a.downloaders = b.downloaders,
a.verified = b.verified
Run Code Online (Sandbox Code Playgroud)
更新 4:
以上所有测试都是在测试机上完成的,但现在我在生产机上做了同样的测试,查询速度非常快。
mysql> UPDATE content_test a JOIN content_csv_dump_temp b
-> ON a.hash = b.hash
-> SET
-> a.uploaders = b.uploaders,
-> a.downloaders = b.downloaders,
-> a.verified = b.verified;
Query OK, 2673528 rows affected (7 min 50.42 sec)
Rows matched: 7044818 Changed: 2673528 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
我为我的错误道歉。最好使用 join 而不是每个记录更新。现在我正在尝试使用 rick_james 建议的索引来改进 mpre,一旦完成基准测试就会更新。
Cra*_*ein 16
根据我的经验,我会使用LOAD DATA INFILE来导入您的 CSV 文件。
LOAD DATA INFILE 语句以非常高的速度将文本文件中的行读取到表中。
我在互联网负载数据示例上找到的示例。我在我的盒子上测试了这个例子并且工作正常
示例表
CREATE TABLE example (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Column2` varchar(14) NOT NULL,
`Column3` varchar(14) NOT NULL,
`Column4` varchar(14) NOT NULL,
`Column5` DATE NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB
Run Code Online (Sandbox Code Playgroud)
示例 CSV 文件
# more /tmp/example.csv
Column1,Column2,Column3,Column4,Column5
1,A,Foo,sdsdsd,4/13/2013
2,B,Bar,sdsa,4/12/2013
3,C,Foo,wewqe,3/12/2013
4,D,Bar,asdsad,2/1/2013
5,E,FOObar,wewqe,5/1/2013
Run Code Online (Sandbox Code Playgroud)
从 MySQL 控制台运行的导入语句
LOAD DATA LOCAL INFILE '/tmp/example.csv'
-> INTO TABLE example
-> FIELDS TERMINATED BY ','
-> LINES TERMINATED BY '\n'
-> IGNORE 1 LINES
-> (id, Column3,Column4, @Column5)
-> set
-> Column5 = str_to_date(@Column5, '%m/%d/%Y');
Run Code Online (Sandbox Code Playgroud)
结果
MySQL [testcsv]> select * from example;
+----+---------+---------+---------+------------+
| Id | Column2 | Column3 | Column4 | Column5 |
+----+---------+---------+---------+------------+
| 1 | | Column2 | Column3 | 0000-00-00 |
| 2 | | B | Bar | 0000-00-00 |
| 3 | | C | Foo | 0000-00-00 |
| 4 | | D | Bar | 0000-00-00 |
| 5 | | E | FOObar | 0000-00-00 |
+----+---------+---------+---------+------------+
Run Code Online (Sandbox Code Playgroud)
IGNORE 只是简单地忽略作为列标题的第一行。
在 IGNORE 之后,我们指定要导入的列(跳过 column2),它与您的问题中的条件之一匹配。
这是直接来自 Oracle 的另一个示例: LOAD DATA INFILE 示例
这应该足以让您入门。
Rol*_*DBA 16
鉴于所有提到的事情,看起来瓶颈是连接本身。
很有可能,您的join_buffer_size可能太低了。
根据关于 MySQL如何使用连接缓冲区缓存的 MySQL 文档
我们只将使用过的列存储在连接缓冲区中,而不是整行。
在这种情况下,让连接缓冲区的键留在 RAM 中。
每个键有 1000 万行乘以 4 个字节。那大约是40M。
尝试在会话中将其提高到 42M(略大于 40M)
SET join_buffer_size = 1024 * 1024 * 42;
UPDATE table1 a JOIN table2 b
ON a.field1 = b.field1
SET
a.field2 = b.field2,
a.field3 = b.field3,
a.field4 = b.field4;
Run Code Online (Sandbox Code Playgroud)
如果这样做成功,请继续将其添加到 my.cnf
[mysqld]
join_buffer_size = 42M
Run Code Online (Sandbox Code Playgroud)
新连接不需要重新启动 mysqld。赶紧跑
mysql> SET GLOBAL join_buffer_size = 1024 * 1024 * 42;
Run Code Online (Sandbox Code Playgroud)
您可以通过调整优化器来操纵连接操作的样式
根据关于Block Nested-Loop 和 Batched Key Access Joins 的MySQL 文档
使用 BKA 时,join_buffer_size 的值定义了每次向存储引擎请求的密钥批次的大小。缓冲区越大,对连接操作的右手表的顺序访问就越多,这可以显着提高性能。
要使用 BKA,必须将 optimizer_switch 系统变量的 batched_key_access 标志设置为 on。BKA 使用 MRR,因此也必须打开 mrr 标志。目前,对 MRR 的成本估算过于悲观。因此,还需要关闭 mrr_cost_based 才能使用 BKA。
同一页面建议这样做:
mysql> SET optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on';
Run Code Online (Sandbox Code Playgroud)
大多数人忘记增加innodb_write_io_threads以更快地将脏页从缓冲池中写入。
[mysqld]
innodb_write_io_threads = 16
Run Code Online (Sandbox Code Playgroud)
您必须重新启动 MySQL 才能进行此更改
| 归档时间: |
|
| 查看次数: |
119803 次 |
| 最近记录: |