如何提高 MySQL 自连接的性能
How to improve MySQL performance on self join
我正在 table 上做一个 self-join 像这样(实际的 table 有更多字段):
id
pagetitle
parent
class_key
1
Page1
0
web
2
Page2
1
web
3
Page3
1
xxx
4
Page4
3
web
5
Page5
4
web
6
Page6
0
alt
我需要查找 class_key
与 parent 记录的 class_key
不匹配的记录(parent 字段是另一条记录的 ID)。带有 0 parent
的记录没有 parent。 parent 和 ID 字段不能为空。并且没有记录的 ID 为 0。所以我需要一个只包含记录 3 和 4 的结果,因为它们有 parent 并且它们的 class_keys
与它们的 parent 不匹配class_key
.
此查询似乎有效:
SELECT
c1.id,
c1.pagetitle,
c1.parent,
c1.context_key,
c2.context_key as parent_context_key
FROM `site_content` c1
INNER JOIN site_content c2
ON
c1.parent > 0
AND c1.parent = c2.id
AND c1.context_key <> c2.context_key
ORDER BY
c1.pagetitle
如果我删除第一个 ON 条件,它似乎也可以工作。当忽略它时,如果我反转剩余的条件,它也会起作用。
令我惊讶的是,PhpMyAdmin 中的三个查询的查询时间非常接近(~015 秒)。我原以为第一个是最快的,因为它首先消除了没有 parent 的记录(不是)。我的实际 table 只有大约 20 行,但代码可能 运行 在非常大的 table 上。
我想我会向比我了解更多的人征求有关此查询的最佳形式的建议,或者更好的查询来完成这项工作。
id
列几乎可以肯定是主键。所以查询规划器可以很容易地从第二个条件c1.parent = c2.id
推断出一个与c2.parent >= 0
冗余的条件:它知道任何匹配第二个条件的行也匹配第一个,所以查询计划可能接近相同.
注意:大型表中的查询计划可能大不相同。 access-cost 配置文件(i/o 和 cpu)在较大的表中有很大不同,因此查询计划器对各种备选计划的权重不同。 (tl;dr 试图从小表中推断出任何关于性能的信息是毫无意义的。)
但保留第一个条件。它使您的查询更容易推理,并且如果新版本有 query-planner 更改,它可能会在某个时候对性能优化派上用场。 SQL 语句及其数据可以持续数十年,比它们 运行 所在的服务器版本要长得多。
我正在 table 上做一个 self-join 像这样(实际的 table 有更多字段):
id | pagetitle | parent | class_key |
---|---|---|---|
1 | Page1 | 0 | web |
2 | Page2 | 1 | web |
3 | Page3 | 1 | xxx |
4 | Page4 | 3 | web |
5 | Page5 | 4 | web |
6 | Page6 | 0 | alt |
我需要查找 class_key
与 parent 记录的 class_key
不匹配的记录(parent 字段是另一条记录的 ID)。带有 0 parent
的记录没有 parent。 parent 和 ID 字段不能为空。并且没有记录的 ID 为 0。所以我需要一个只包含记录 3 和 4 的结果,因为它们有 parent 并且它们的 class_keys
与它们的 parent 不匹配class_key
.
此查询似乎有效:
SELECT
c1.id,
c1.pagetitle,
c1.parent,
c1.context_key,
c2.context_key as parent_context_key
FROM `site_content` c1
INNER JOIN site_content c2
ON
c1.parent > 0
AND c1.parent = c2.id
AND c1.context_key <> c2.context_key
ORDER BY
c1.pagetitle
如果我删除第一个 ON 条件,它似乎也可以工作。当忽略它时,如果我反转剩余的条件,它也会起作用。
令我惊讶的是,PhpMyAdmin 中的三个查询的查询时间非常接近(~015 秒)。我原以为第一个是最快的,因为它首先消除了没有 parent 的记录(不是)。我的实际 table 只有大约 20 行,但代码可能 运行 在非常大的 table 上。
我想我会向比我了解更多的人征求有关此查询的最佳形式的建议,或者更好的查询来完成这项工作。
id
列几乎可以肯定是主键。所以查询规划器可以很容易地从第二个条件c1.parent = c2.id
推断出一个与c2.parent >= 0
冗余的条件:它知道任何匹配第二个条件的行也匹配第一个,所以查询计划可能接近相同.
注意:大型表中的查询计划可能大不相同。 access-cost 配置文件(i/o 和 cpu)在较大的表中有很大不同,因此查询计划器对各种备选计划的权重不同。 (tl;dr 试图从小表中推断出任何关于性能的信息是毫无意义的。)
但保留第一个条件。它使您的查询更容易推理,并且如果新版本有 query-planner 更改,它可能会在某个时候对性能优化派上用场。 SQL 语句及其数据可以持续数十年,比它们 运行 所在的服务器版本要长得多。