MySQL 优化 - 大表连接
Posted
技术标签:
【中文标题】MySQL 优化 - 大表连接【英文标题】:MySQL optimization - large table joins 【发布时间】:2012-05-15 15:57:07 【问题描述】:首先是所涉及表格的简化版本。
tbl_map
大约有 4,000,000 行,tbl_1
大约有 120 行,tbl_2
大约有 5,000,000 行。鉴于 Google、Yahoo! 等使用更大的数据集,我知道数据不应考虑那么大。所以我只是假设我错过了一些东西。
CREATE TABLE `tbl_map` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`tbl_1_id` bigint(20) DEFAULT '-1',
`tbl_2_id` bigint(20) DEFAULT '-1',
`rating` decimal(3,3) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `tbl_1_id` (`tbl_1_id`),
KEY `tbl_2_id` (`tbl_2_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `tbl_1` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `tbl_2` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`data` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
感兴趣的查询:也可以用ORDERY BY t.id DESC
代替ORDERY BY t.id DESC
。该查询需要 5~10 秒,并且在用户查看此页面时会导致相当长的等待时间。
EXPLAIN SELECT t.data, t.id , tm.rating
FROM tbl_2 AS t
JOIN tbl_map AS tm
ON t.id = tm.tbl_2_id
WHERE tm.tbl_1_id =94
AND tm.rating IS NOT NULL
ORDER BY t.id DESC
LIMIT 200
1 SIMPLE tm ref tbl_1_id, tbl_2_id tbl_1_id 9 const 703438 Using where; Using temporary; Using filesort
1 SIMPLE t eq_ref PRIMARY PRIMARY 8 tm.tbl_2_id 1
我只想加快查询速度,确保我有正确的索引等。 我感谢 DB 大师的任何建议!谢谢。
【问题讨论】:
【参考方案1】:SUGGESTION : 索引表如下:
ALTER TABLE tbl_map ADD INDEX (tbl_1_id,rating,tbl_2_id);
【讨论】:
感谢您的快速回答 :) 我会试一试,让您知道它是如何工作的。很高兴收到一位真正的 DBA 的来信! 索引绝对是一个巨大的帮助。但是,我现在对 SQL 语句的重构不返回任何内容。我会继续看看这是否只是我的一个错误。 它将留下评级为 NULL 的连接条目。实际上,添加您提到的索引后,我的原始查询和 DRapp 工作正常。 :) tm 子查询明确表示AND rating IS NOT NULL
。当且仅当t.id = tm.tbl_2_id
对给定行失败时,tm 子查询才会产生 NULL 评级。
据我了解,第一个选择从tbl_2
中提取 lass 200 个条目,来自 tm 的 LEFT JOIN
s。因为它是LEFT JOIN
,所以当第二个 Select 查询没有产生结果(即 rating IS NULL)时,NULL 将作为 tm.rating 返回。【参考方案2】:
按照 Rolando 的说法,是的,您肯定需要在地图表上建立索引,但我会扩展到还包括 tbl_2_id,它用于表 2 的 ID 的 ORDER BY 子句(与地图在同一个表中,所以只需使用该索引。此外,由于索引现在包含所有 3 个字段,并且基于关键字搜索的 ID 和评级为空(或不)的标准,因此第三个元素已经为您的 ORDER BY 子句提供了它们.
INDEX (tbl_1_id,rating, tbl_2_id);
然后,我将查询作为
SELECT STRAIGHT_JOIN
t.data,
t.id ,
tm.rating
FROM
tbl_map tm
join tbl_2 t
on tm.tbl_2_id = t.id
WHERE
tm.tbl_1_id = 94
AND tm.rating IS NOT NULL
ORDER BY
tm.tbl_2_id DESC
LIMIT 200
【讨论】:
在添加 Rolando 提到的 INDEX 后,此查询从 60 秒变为 1.2 秒。那很好。我预先解释了它,它也显示出更好的结果。谢谢 @KennyCason,在索引上还可以,但是我的版本显然是如何获得赞誉的……IT 的解释和整体性能与 1.2 相比如何。那么哪个结果更好...... 我主要排除了您的查询,因为查询有效,但是是的,鉴于最终 Rolando 首先提到了 INDEXing,我可以给予他信任。至于查询性能,在对行进行索引后,我们的查询运行大致相同。谢谢。以上是关于MySQL 优化 - 大表连接的主要内容,如果未能解决你的问题,请参考以下文章