我给这个查询PostgreSQL的9.2优化:PostgreSQL的查询优化无内/外连接允许
SELECT C.name, COUNT(DISTINCT I.id) AS NumItems, COUNT(B.id)
FROM Categories C INNER JOIN Items I ON(C.id = I.category)
INNER JOIN Bids B ON (I.id = B.item_id)
GROUP BY C.name
由于我校任务的一部分。
我已经建立在相应的表中的这些索引:items(category)
- > 2ndary B +树,bids(item_id)
- > 2ndary B +树,并categories(id)
- >初级这里指数,
怪异的部分是,PostgreSQL的正在对我的Items,Categories和Bids表进行顺序扫描,当我设置enable_seqscan=off
时,索引搜索结果比下面的结果更可怕。
当我在PostgreSQL中运行解释时,结果如下:请不要删除它们,因为它们是重要的!
GroupAggregate (cost=119575.55..125576.11 rows=20 width=23) (actual time=6912.523..9459.431 rows=20 loops=1)
Buffers: shared hit=30 read=12306, temp read=6600 written=6598
-> Sort (cost=119575.55..121075.64 rows=600036 width=23) (actual time=6817.015..8031.285 rows=600036 loops=1)
Sort Key: c.name
Sort Method: external merge Disk: 20160kB
Buffers: shared hit=30 read=12306, temp read=6274 written=6272
-> Hash Join (cost=9416.95..37376.03 rows=600036 width=23) (actual time=407.974..3322.253 rows=600036 loops=1)
Hash Cond: (b.item_id = i.id)
Buffers: shared hit=30 read=12306, temp read=994 written=992
-> Seq Scan on bids b (cost=0.00..11001.36 rows=600036 width=8) (actual time=0.009..870.898 rows=600036 loops=1)
Buffers: shared hit=2 read=4999
-> Hash (cost=8522.95..8522.95 rows=50000 width=19) (actual time=407.784..407.784 rows=50000 loops=1)
Buckets: 4096 Batches: 2 Memory Usage: 989kB
Buffers: shared hit=28 read=7307, temp written=111
-> Hash Join (cost=1.45..8522.95 rows=50000 width=19) (actual time=0.082..313.211 rows=50000 loops=1)
Hash Cond: (i.category = c.id)
Buffers: shared hit=28 read=7307
-> Seq Scan on items i (cost=0.00..7834.00 rows=50000 width=8) (actual time=0.004..144.554 rows=50000 loops=1)
Buffers: shared hit=27 read=7307
-> Hash (cost=1.20..1.20 rows=20 width=19) (actual time=0.062..0.062 rows=20 loops=1)
Buckets: 1024 Batches: 1 Memory Usage: 1kB
Buffers: shared hit=1
-> Seq Scan on categories c (cost=0.00..1.20 rows=20 width=19) (actual time=0.004..0.028 rows=20 loops=1)
Buffers: shared hit=1
Total runtime: 9473.257 ms
查看this plan on explain.depesz.com。
我只是想知道为什么会发生这种情况,即为什么索引使查询速度与顺序扫描相比非常慢。
编辑: 我想我已经设法通过postgresql文档发现了几个东西。 Postgresql决定对某些表格(如出价和项目)执行seq扫描,因为它预测它必须检索表格中的每一行(比较实际时间之前的括号内的行数和实际时间中的行数部分)。顺序扫描在检索所有行时效果更好。那么在这一方面什么都做不了。
我为categories(name)
创建了额外的索引,下面的结果就是我的。它以某种方式改进,但现在散列连接被替换为嵌套循环。任何线索为什么?
GroupAggregate (cost=0.00..119552.02 rows=20 width=23) (actual time=617.330..7725.314 rows=20 loops=1)
Buffers: shared hit=178582 read=37473 written=14, temp read=2435 written=436
-> Nested Loop (cost=0.00..115051.55 rows=600036 width=23) (actual time=0.120..6186.496 rows=600036 loops=1)
Buffers: shared hit=178582 read=37473 written=14, temp read=2109 written=110
-> Nested Loop (cost=0.00..26891.55 rows=50000 width=19) (actual time=0.066..2827.955 rows=50000 loops=1)
Join Filter: (c.id = i.category)
Rows Removed by Join Filter: 950000
Buffers: shared hit=2 read=7334 written=1, temp read=2109 written=110
-> Index Scan using categories_name_idx on categories c (cost=0.00..12.55 rows=20 width=19) (actual time=0.039..0.146 rows=20 loops=1)
Buffers: shared hit=1 read=1
-> Materialize (cost=0.00..8280.00 rows=50000 width=8) (actual time=0.014..76.908 rows=50000 loops=20)
Buffers: shared hit=1 read=7333 written=1, temp read=2109 written=110
-> Seq Scan on items i (cost=0.00..7834.00 rows=50000 width=8) (actual time=0.007..170.464 rows=50000 loops=1)
Buffers: shared hit=1 read=7333 written=1
-> Index Scan using bid_itemid_idx on bids b (cost=0.00..1.60 rows=16 width=8) (actual time=0.016..0.036 rows=12 loops=50000)
Index Cond: (item_id = i.id)
Buffers: shared hit=178580 read=30139 written=13
Total runtime: 7726.392 ms
看看计划here如果更好。
我已经设法通过在类别(id)和items(category)
上创建索引将它缩小到114062.92。 Postgresql使用这两个索引来达到114062.92的成本。 但是,现在postgresql正在和我一起玩游戏,不使用索引!为什么它很奇怪?
要按名称分组,它虽然要按名称排序,如果你在categories.name上添加索引,它可能会更好。我还会在items.id上放置一个索引来加速独立(i.id)和加入到b.item_id。 –
另外,请记住,Postgres“解释计划”可能在您进行“真空分析”之后才会给您带来好的结果。 –
感谢回复@PaulTomblin。 Yeap我确信我在解释计划之前使用了真空分析以获得准确的结果。 项目。id是items表的主键,因此它将包含聚集索引。 – ImNoob