Dio*_*lis 3 mysql mariadb join partitioning
我正在尝试将以下连接查询作为 MariaDB 10.1.26 上更复杂查询的一部分运行。
select distinct
project_commits.project_id,
date_format(created_at, '%x%v1') as week_commit
from project_commits
left join commits
on project_commits.commit_id = commits.id;
Run Code Online (Sandbox Code Playgroud)
两个连接字段都被索引。但是,连接涉及对 的完整扫描project_commits和索引查找commits。的输出证实了这一点EXPLAIN。
+------+-------------+-----------------+--------+---------------+---------+---------+-------------------------------------+------------+-----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-----------------+--------+---------------+---------+---------+-------------------------------------+------------+-----------------+
| 1 | SIMPLE | project_commits | ALL | NULL | NULL | NULL | NULL | 5417294109 | Using temporary |
| 1 | SIMPLE | commits | eq_ref | PRIMARY | PRIMARY | 4 | ghtorrent.project_commits.commit_id | 1 | |
+------+-------------+-----------------+--------+---------------+---------+---------+-------------------------------------+------------+-----------------+
Run Code Online (Sandbox Code Playgroud)
两个表的大小都比较大:project_commits包含50亿行和commits8.47亿行。此外服务器的内存大小相对较小(16GB)。这可能意味着索引查找会访问(不幸的是磁盘)磁盘,因此性能会受到重创。根据pmonitor run 在生成的临时表上的输出,已经运行了半天多的查询,还需要 373 小时才能完成。
/home/mysql/ghtorrent/project_commits#P#p0.MYD 6.68% ETA 373:38:11
Run Code Online (Sandbox Code Playgroud)
我是否可以通过对表进行分区以某种方式提高查询的性能,以便可以在内存中执行连接,或者强制 MySQL 执行排序合并连接?由于运行替代策略所涉及的时间可能需要数小时,我宁愿有一个建议,而不是尝试。
从 EXPLAIN 计划的外观来看,您正在对project_commits.
从查询的外观上来看,我推测有从一到多的关系commits来project_commits。我看到的问题是您的查询正在以多对一的方式收集数据。
您也在使用LEFT JOIN.
您的查询是这样说的:
向我展示所有
project_commits连接到或孤立的commits
相反,您可能希望查询显示:
显示所有
project_commits相关的commits
EXPLAIN select distinct
project_commits.project_id,
date_format(created_at, '%x%v1') as week_commit
from commits
left join project_commits
on commits.id = project_commits.commit_id;
Run Code Online (Sandbox Code Playgroud)
INNER JOINEXPLAIN select distinct
project_commits.project_id,
date_format(created_at, '%x%v1') as week_commit
from project_commits
inner join commits
on project_commits.commit_id = commits.id;
Run Code Online (Sandbox Code Playgroud)
created_at索引如果您已经有一个索引,created_at或者您已经有一个第一列是 的复合索引created_at,请跳过此建议。
ALTER TABLE `project_commits` ADD INDEX created_at_ndx (`created_at`);
Run Code Online (Sandbox Code Playgroud)
添加索引将改变EXPLAIN执行索引扫描而不是表扫描的计划
JOIN行为您可以通过调整优化器来操纵连接操作的样式
根据关于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)
注意:我不知道我的建议会有什么期望。毕竟,您LEFT JOIN就像一个迭代笛卡尔连接,具有制作以下临时表的潜力
正在查找 45.73 Quintillion 行(54 亿 X 08.47 亿)
玩得开心,让我们知道你发现了什么
| 归档时间: |
|
| 查看次数: |
4148 次 |
| 最近记录: |