Nie*_*ian 38 postgresql performance database-design postgresql-performance
我对查看EXPLAIN ANALYZE结果不是很熟悉,我的查询太慢了,我遇到了很大的问题.我试图阅读如何解释解释查询的结果,但我仍然不知道我应该寻找什么,以及可能出错的地方.我有一种感觉,某处有一些大红灯闪烁,我只是看不到它.
所以查询很简单,看起来像这样:
EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE LIMIT 25 OFFSET 0
Run Code Online (Sandbox Code Playgroud)
结果如下:
Limit (cost=0.00..161.07 rows=25 width=1245) (actual time=35.232..38.694 rows=25 loops=1)
-> Index Scan using index_cars_onsale_on_brand_and_model_name on cars (cost=0.00..1179.06 rows=183 width=1245) (actual time=35.228..38.652 rows=25 loops=1)
Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text))
Filter: has_auto_gear"
Total runtime: 38.845 ms
Run Code Online (Sandbox Code Playgroud)
一点背景:我在Postgresql 9.1.6上,在Herokus专用数据库上运行.我的数据库有大约7,5Gb内存,表车包含3,1M行,并且行中有2,0M的行有sales_state ='onsale'.该表有170列.它使用的索引如下所示:
CREATE INDEX index_cars_onsale_on_brand_and_model_name
ON cars
USING btree
(brand COLLATE pg_catalog."default" , model_name COLLATE pg_catalog."default" )
WHERE sales_state::text = 'onsale'::text;
Run Code Online (Sandbox Code Playgroud)
有人看到一些很明显的问题吗?
编辑:
SELECT pg_relation_size('cars'), pg_total_relation_size('cars');
Run Code Online (Sandbox Code Playgroud)
pg_relation_size:2058444800 pg_total_relation_size:4900126720
SELECT pg_relation_size('index_cars_onsale_on_brand_and_model_name');
Run Code Online (Sandbox Code Playgroud)
pg_relation_size:46301184
SELECT avg(pg_column_size(cars)) FROM cars limit 5000;
Run Code Online (Sandbox Code Playgroud)
平均值:636.9732567210792995
没有限制:
EXPLAIN ANALYZE SELECT "cars".* FROM "cars" WHERE "cars"."sales_state" = 'onsale' AND "cars"."brand" = 'BMW' AND "cars"."model_name" = '318i' AND "cars"."has_auto_gear" = TRUE
Bitmap Heap Scan on cars (cost=12.54..1156.95 rows=183 width=4) (actual time=17.067..55.198 rows=2096 loops=1)
Recheck Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text) AND ((sales_state)::text = 'onsale'::text))
Filter: has_auto_gear
-> Bitmap Index Scan on index_cars_onsale_on_brand_and_model_name (cost=0.00..12.54 rows=585 width=0) (actual time=15.211..15.211 rows=7411 loops=1)"
Index Cond: (((brand)::text = 'BMW'::text) AND ((model_name)::text = '318i'::text))
Total runtime: 56.851 ms
Run Code Online (Sandbox Code Playgroud)
Cra*_*ger 28
虽然对于像这样的简单计划不那么有用,但http://explain.depesz.com非常有用.请参见http://explain.depesz.com/s/t4fi.请注意"统计信息"标签和"选项"下拉菜单.
有关此计划的注意事项:
估计的行数(183)与实际行数(25)相当.它不是数百倍,也不是1.当涉及行数估计或"1 vs 1"问题时,您对数量级更感兴趣.(你甚至不需要"足够接近政府工作"的准确性 - "足够接近军事承包会计"会这样做).选择性估计和统计似乎是合理的.
它使用了提供的两列部分索引(index scan using index_cars_onsale_on_brand_and_model_name),因此它与部分索引条件匹配.你可以在中看到Filter: has_auto_gear.还显示了索引搜索条件.
鉴于表的行数意味着索引相当大,特别是因为它超过两列,查询性能看起来很合理.匹配的行将被分散,因此每行可能还需要单独的页面读取.
我觉得这里没有错.不过,这个查询可能会从PostgreSQL 9.2的仅索引扫描中受益匪浅.
这里可能存在一些表膨胀,但考虑到2列索引和行数,响应时间并非完全不合理,特别是对于具有170(!!)列的表,每个列可能适合相对较少的元组页.如果您能够承受一些停机时间,请尝试VACUUM FULL重新组织表并重建索引.这将在重建它时将表独占锁定一段时间.如果你不能承受的停机时间,见pg_reorg和/或CREATE INDEX CONCURRENTLY和ALTER INDEX ... RENAME TO.
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)有时您可能会发现更多信息,因为它可以显示缓冲区访问等.
可以使此查询更快的一个选项(尽管它可能会在某种程度上减慢其他查询的速度)是对表进行分区brand并启用constraint_exclusion.请参阅分区.
| 归档时间: |
|
| 查看次数: |
28928 次 |
| 最近记录: |