相同 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 以了解实际效果。
我有一个名为 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 以了解实际效果。