LEFT JOIN的速度在同一个表中 - Mysql

时间:2016-05-03 14:28:29

标签: mysql performance left-join

我有一张叫做PRODUCTS的桌子。它有一个语言字段。我想列出其他语言中缺少转录(相应ID)的language = 'es'行。我尝试了以下(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

3 个答案:

答案 0 :(得分:1)

我的猜测是由于桌面上缺少索引而发生这种情况。

尝试在(id_productslanguage)上添加索引,这样可以加快查询速度。

此外,您可以尝试使用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)

答案 1 :(得分:1)

更好的指数

复合索引的顺序会更快:

INDEX(language, id_products)

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

不要被查询缓存误导

如果您的时间小于1毫秒,您可能会从“查询缓存”中得到答案。为了测试,请通过

来避免它
SELECT SQL_NO_CACHE ...

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

答案 2 :(得分:1)

在查询中进行过滤的位置有些奇怪。 您将获得所有产品的列表,无论来源是否为'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;

正如其他人指出的那样,你还需要一个关于源语言过滤的语言索引,并且取决于你的tabell的大小,也可以在id_products上。

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

请参阅此sql fiddle以查看其实际效果。