我有19年的Oracle和MySQL经验(DBA和开发),我是Postgres的新手,所以我可能会遗漏一些明显的东西。但我不能让这个查询做我想做的事。
NOTE: This query is running on an EngineYard Postgres instance. I am not immediately aware of the parameters it has set up. Also, columns applicable_type and status in the items table are of extension type citext.
以下查询可能需要超过60秒才能返回行:
SELECT items.item_id,
CASE when items.sku is null then items.title else concat(item.title, ' (SKU: ', items.sku, ')') END title,
items.listing_status, items.updated_at, items.id,
items.sku, count(details.id) detail_count
FROM "items" LEFT OUTER JOIN details ON details.applicable_id = items.id
and details.applicable_type = 'Item'
and details.status = 'Valid'
LEFT OUTER JOIN products ON products.id = items.product_id
WHERE "items"."user_id" = 3
GROUP BY items.id
ORDER BY title asc
LIMIT 25 OFFSET 0
details
表包含6.5M行。它LEFT OUTER JOIN
对applicable_id
进行顺序扫描。基数方面,该列在6.5M行中具有120K不同的可能性。
我在details
上有一个btree索引,其中包含以下列:
applicable_id
applicable_type
status
但实际上,applicable_id
和applicable_type
基数较低。
我的explain analyze
看起来像这样:
Limit (cost=247701.59..247701.65 rows=25 width=118) (actual time=28781.090..28781.098 rows=25 loops=1)
-> Sort (cost=247701.59..247703.05 rows=585 width=118) (actual time=28781.087..28781.090 rows=25 loops=1)
Sort Key: (CASE WHEN (items.sku IS NULL) THEN (items.title)::text ELSE pg_catalog.concat(items.title, ' (SKU: ', items.sku, ')') END)
Sort Method: top-N heapsort Memory: 30kB
-> HashAggregate (cost=247677.77..247685.08 rows=585 width=118) (actual time=28779.658..28779.974 rows=664 loops=1)
-> Hash Right Join (cost=2069.47..247645.64 rows=6425 width=118) (actual time=17798.898..28742.395 rows=60047 loops=1)
Hash Cond: (details.applicable_id = items.id)
-> Seq Scan on details (cost=0.00..220591.65 rows=6645404 width=8) (actual time=6.272..27702.717 rows=6646205 loops=1)
Filter: ((applicable_type = 'Listing'::citext) AND (status = 'Valid'::citext))
Rows Removed by Filter: 942
-> Hash (cost=2062.16..2062.16 rows=585 width=118) (actual time=1.286..1.286 rows=664 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 90kB
-> Bitmap Heap Scan on items (cost=16.87..2062.16 rows=585 width=118) (actual time=0.157..0.748 rows=664 loops=1)
Recheck Cond: (user_id = 3)
-> Bitmap Index Scan on index_items_on_user_id (cost=0.00..16.73 rows=585 width=0) (actual time=0.141..0.141 rows=664 loops=1)
Index Cond: (user_id = 3)
总运行时间:28781.238 ms
答案 0 :(得分:3)
你有一个表达式的索引产生标题吗?更好的是,一个(user_id,title_expression)。
如果没有,这可能是一个很好的添加,以便nestloop通过索引扫描的前25行,看到Postgres无法合理地猜测哪些随机25行(因此seq扫描你当前
。需要加入联名表答案 1 :(得分:1)
我认为您只需要在applicable_id列上有一个索引(没有applicable_type,status列)。 您可能还需要增加default_statistics_target param(系统范围或更好,仅适用于applicable_id列),因此postgresql最好猜测加入时的行数。