1

我有这个查询

SELECT "items".*
FROM
    "items"
    INNER JOIN
    item_mods ON item_mods.item_id = items.id AND item_mods.mod_id = 15
WHERE (items.league_id = 1) AND (items.item_type_id = 11) AND (num_sockets >= 2)
ORDER BY item_mods.total_value DESC
LIMIT 25

这是解释http://explain.depesz.com/s/dbf

"Limit  (cost=55739.84..55739.90 rows=25 width=554) (actual time=18065.470..18065.478 rows=25 loops=1)"
"  ->  Sort  (cost=55739.84..55741.90 rows=824 width=554) (actual time=18065.468..18065.471 rows=25 loops=1)"
"        Sort Key: item_mods.total_value"
"        Sort Method: top-N heapsort  Memory: 37kB"
"        ->  Nested Loop  (cost=5871.95..55716.59 rows=824 width=554) (actual time=285.806..18055.589 rows=610 loops=1)"
"              ->  Bitmap Heap Scan on items  (cost=5871.52..20356.70 rows=4339 width=550) (actual time=201.543..10028.684 rows=9945 loops=1)"
"                    Recheck Cond: ((item_type_id = 11) AND (num_sockets >= 2))"
"                    Rows Removed by Index Recheck: 4120"
"                    Filter: (league_id = 1)"
"                    Rows Removed by Filter: 1125"
"                    ->  BitmapAnd  (cost=5871.52..5871.52 rows=4808 width=0) (actual time=199.322..199.322 rows=0 loops=1)"
"                          ->  Bitmap Index Scan on index_items_on_item_type_id  (cost=0.00..289.61 rows=15625 width=0) (actual time=38.699..38.699 rows=16018 loops=1)"
"                                Index Cond: (item_type_id = 11)"
"                          ->  Bitmap Index Scan on index_items_on_num_sockets  (cost=0.00..5579.49 rows=301742 width=0) (actual time=158.441..158.441 rows=301342 loops=1)"
"                                Index Cond: (num_sockets >= 2)"
"              ->  Index Scan using index_item_mods_on_item_id on item_mods  (cost=0.43..8.14 rows=1 width=8) (actual time=0.803..0.803 rows=0 loops=9945)"
"                    Index Cond: (item_id = items.id)"
"                    Filter: (mod_id = 15)"
"                    Rows Removed by Filter: 9"
"Total runtime: 18065.773 ms"

如何提高此查询的速度?我注意到索引扫描中有一个循环 > 9000 次

4

3 回答 3

2

您的查询速度慢的原因是因为您想要返回数据的方式没有索引。

注意“位图索引扫描”,它说,我知道你有一个索引,但我必须查看整个表才能找到我需要的行(因此总行扫描高达 301742!)。这可能是因为您要求的其他列的组合以及您正在应用的约束,即 item_mods.mod_id = 15

尝试:

  1. "items".* - 只选择您需要的列而不是所有内容。

  2. 在以下位置创建索引: item_mods.item_id AND item_mods.mod_id

  3. 在以下位置创建索引: items.league_id AND items.item_type_id AND num_sockets(假设 num_sockets 在同一张桌子上)

有什么性能差异吗?

于 2014-03-04T17:48:14.967 回答
1

这只会缩短和清理语法,但不会实质性地改变任何东西:

SELECT i.*
FROM   items     i
JOIN   item_mods m ON m.item_id = i.id
WHERE  i.league_id = 1
AND    i.item_type_id = 11
AND    i.num_sockets >= 2
AND    m.mod_id = 15
ORDER  BY m.total_value DESC
LIMIT  25;

像这样的查询很难优化。Postgres 不能只从索引顶部读取。由于您按 中的列进行排序item_mods,但最具选择性的条件是 on items,因此也很难定制一个更有帮助的索引。

当然,您可以优化任一表上的索引。但是如果没有额外的信息来提供给查询,它不会变得便宜。在 Postgres 知道获胜者之前,必须阅读所有符合条件的行。

我们在 dba.SE 上针对这个相关问题开发了解决方案。复杂
的东西:空间索引能否帮助“范围-按-限制”查询

于 2014-03-04T23:16:01.980 回答
0

下面的查询应该提供更好的性能,因为过滤是在加入之前完成的。

   SELECT t.* 
   FROM
   (
     SELECT items.* FROM items
     WHERE  (items.league_id = 1) AND (items.item_type_id = 11) 
   ) t 
   INNER JOIN 
   (
      SELECT item_mods.*
      FROM item_mods
      WHERE item_mods.mod_id = 15 
   ) s
   ON s.item_id = t.id 
   WHERE (num_sockets >= 2)
   ORDER BY item_mods.total_value DESC
   LIMIT 25

num_sockets>=2如果知道它属于哪个表,也可以包含在一些内部查询中。

请让我知道它是否表现更好。

于 2014-03-04T17:41:23.680 回答