我有这个查询
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次
答案 0 :(得分:2)
查询速度慢的原因是因为没有索引可以返回数据。
注意“位图索引扫描”,它说,我知道你有一个索引,但我必须查看整个表以找到我需要的行(因此总行扫描最多为301742!)。这可能是因为您要求的其他列的组合以及您正在应用的约束,即item_mods.mod_id = 15
尝试:
“items”。* - 只选择您需要的列而不是所有列。
在以下项目上创建索引:item_mods.item_id AND item_mods.mod_id
在:items.league_id和items.item_type_id AND num_sockets上创建索引(假设num_sockets在同一个表中)
任何表现差异?
答案 1 :(得分: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
中的列进行排序,但最具选择性的条件是items
,因此很难定制一个可以帮助更多的索引。
当然,您可以优化任一表上的索引。但是如果没有其他信息可以提供给查询,它就不会便宜。 所有符合条件的行必须在Postgres知道获胜者之前阅读。
我们已经在dba.SE上根据这个相关问题开发了解决方案。复杂的东西:
Can spatial index help a “range - order by - limit” query
答案 2 :(得分: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
也可以包含在某个内部查询中。
如果效果更好,请告诉我。