如何提高 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 语句及其数据可以持续数十年,比它们 运行 所在的服务器版本要长得多。