【问题标题】:Why is this SQL query SO slow?为什么这个 SQL 查询这么慢?
【发布时间】:2014-03-12 06:33:23
【问题描述】:

我正在运行这个查询:

SELECT DISTINCT "items"."id" 
FROM "items" 
LEFT OUTER JOIN "item_explicit_mods" ON "item_explicit_mods"."item_id" = "items"."id" 
LEFT OUTER JOIN "explicit_mods" ON "explicit_mods"."id" = "item_explicit_mods"."explicit_mod_id" 
LEFT OUTER JOIN "item_implicit_mods" ON "item_implicit_mods"."item_id" = "items"."id" 
LEFT OUTER JOIN "implicit_mods" ON "implicit_mods"."id" = "item_implicit_mods"."implicit_mod_id" 
LEFT OUTER JOIN "shops" ON "shops"."id" = "items"."shop_id" 
WHERE ((item_explicit_mods.explicit_mod_id = 35 
        AND item_explicit_mods.primary_value >= 5 AND item_explicit_mods.primary_value <= 6) 
    OR (item_explicit_mods.explicit_mod_id = 48)) 
GROUP BY items.id 
HAVING COUNT(item_explicit_mods.id) = 2 
ORDER BY "items"."created_at" 
ASC LIMIT 100

Sqlite 解释正在产生这个

0|0|0|SCAN TABLE items USING INTEGER PRIMARY KEY (~1000000 rows)
0|1|1|SEARCH TABLE item_explicit_mods USING AUTOMATIC COVERING INDEX (explicit_mod_id=?) (~7 rows)
0|1|1|SEARCH TABLE item_explicit_mods USING AUTOMATIC COVERING INDEX (explicit_mod_id=?) (~7 rows)
0|2|2|SEARCH TABLE explicit_mods USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|3|3|SEARCH TABLE item_implicit_mods USING AUTOMATIC COVERING INDEX (item_id=?) (~7 rows)
0|4|4|SEARCH TABLE implicit_mods USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|5|5|SEARCH TABLE shops USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
0|0|0|USE TEMP B-TREE FOR DISTINCT
0|0|0|USE TEMP B-TREE FOR ORDER BY

此查询运行时间超过 10 秒。知道为什么要对主键进行 SCAN 吗?

【问题讨论】:

  • 当您已经按同一列分组时,为什么还要使用distinct
  • 这是 ruby​​ on rails activerecord 产生的查询
  • 如果您将where 条件更改为两个条件之一,这需要多长时间?有时,or 可能会给优化器带来问题。

标签: sql sqlite query-optimization


【解决方案1】:

尝试将您的查询更改为此

SELECT "items"."id" 
FROM "items" 
INNER JOIN "item_explicit_mods" ON "item_explicit_mods"."item_id" = "items"."id" AND (((item_explicit_mods.explicit_mod_id = 35 
        AND item_explicit_mods.primary_value >= 5 AND item_explicit_mods.primary_value <= 6) 
    OR (item_explicit_mods.explicit_mod_id = 48)) )
LEFT OUTER JOIN "explicit_mods" ON "explicit_mods"."id" = "item_explicit_mods"."explicit_mod_id" 
LEFT OUTER JOIN "item_implicit_mods" ON "item_implicit_mods"."item_id" = "items"."id" 
LEFT OUTER JOIN "implicit_mods" ON "implicit_mods"."id" = "item_implicit_mods"."implicit_mod_id" 
LEFT OUTER JOIN "shops" ON "shops"."id" = "items"."shop_id"  
GROUP BY items.id 
HAVING COUNT(item_explicit_mods.id) = 2 
ORDER BY "items"."created_at" 
ASC LIMIT 100

【讨论】:

    【解决方案2】:

    知道为什么要对主键进行 SCAN 吗?

    我想是因为你这样做:

    SELECT DISTINCT "items"."id" 
    

    该表的id 列是主键。您正在寻找引用连接中其他表的不同标识符。因此,主键上有一个 SCAN。

    此外,您为什么要对结果进行分组 GROUP BY items.id 而您只是在寻找不同的标识符?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-11
      • 2020-03-19
      • 2011-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多