相同 table - Mysql 中的 LEFT JOIN 速度

Speed of LEFT JOIN in the same table - Mysql

我有一个名为 PRODUCTS 的 table。它有一个字段语言。我想列出 language = 'es' 的所有行,这些行确实缺少其他语言的翻译(相应的 ID)。我尝试了以下方法(id_products 是同一产品不同语言的关键相关行)。它非常慢(几千行几秒钟):

SELECT
    *
FROM
    products AS source
    LEFT JOIN products AS target ON source.id_products = target.id_products
    AND source.`language` = 'es'
    AND target.`language` = 'en'
WHERE
    target.id_products IS NULL

我猜这是由于 table 上缺少索引所致。

尝试在 (id_products,language) 上添加索引,这应该会加快您的查询速度。

此外,您可以尝试使用 NOT EXISTS() 而不是左连接,也许它也会加快速度:

SELECT * FROM products t
WHERE t.language = 'es'
 AND NOT EXISTS(SELECT 1 FROM products s
                WHERE s.language = 'en'
                  and s.id_products = t.id_products)

更好的指数

按照这个顺序使用复合索引会更快:

INDEX(language, id_products)

查询将从 source 开始。为此,它需要查看 language = 'es' 然后 进入 target 的行。对于 target,索引列的顺序无关紧要。

不要被查询缓存误导

如果你得到的时间少于 1 毫秒,你可能会从 "Query cache" 得到答案。为了测试,通过做

来避免它
SELECT SQL_NO_CACHE ...

SELECT * ... 没有用,因为您只需要 source 列,而不是 target 中的所有 NULLs。所以要么说 SELECT source.* 要么只拼出你想要的列。

您在查询中的过滤位置有些奇怪。 您将获得所有产品的列表,无论来源是否在 'es' 中。为了清楚起见,我总是建议将所有 ON 条件放在括号内。

SELECT *
  FROM products AS source
  LEFT JOIN products AS target 
       ON (source.id_products = target.id_products AND target.language = 'en')
 WHERE source.language = 'es'
   AND target.id_products IS NULL;

正如其他人指出的那样,您还需要一个语言索引来过滤源代码,并且取决于您的 tabel 有多大,id_products。

alter table products add index search_index (language, id_products);

查看此 sql fiddle 以了解实际效果。