Exe*_*ian 21 postgresql performance index optimization postgresql-performance
2020-08-04 更新:
由于显然仍在定期查看此答案,因此我想提供有关情况的最新信息。我们目前正在使用带有表分区的 PG 11,timestamp并且可以轻松处理表中的数十亿行。仅索引扫描可以挽救生命,没有它就不可能。
使用 PostgreSQL 9.2,我在相对较大的表(200 多万行)上进行慢速查询时遇到问题。我没有尝试任何疯狂的事情,只是增加了历史价值。下面是查询和查询计划输出。
我的表布局:
Table "public.energy_energyentry"
Column | Type | Modifiers
-----------+--------------------------+-----------------------------------------------------------------
id | integer | not null default nextval('energy_energyentry_id_seq'::regclass)
prop_id | integer | not null
timestamp | timestamp with time zone | not null
value | double precision | not null
Indexes:
"energy_energyentry_pkey" PRIMARY KEY, btree (id)
"energy_energyentry_prop_id" btree (prop_id)
"energy_energyentry_prop_id_timestamp_idx" btree (prop_id, "timestamp")
Foreign-key constraints:
"energy_energyentry_prop_id_fkey" FOREIGN KEY (prop_id) REFERENCES gateway_peripheralproperty(id) DEFERRABLE INITIALLY DEFERRED
Run Code Online (Sandbox Code Playgroud)
数据范围从2012-01-01至今,新数据不断增加。prop_id外键中大约有 2.2k 个不同的值,均匀分布。
我注意到行估计值相差不远,但成本估计值似乎大了 4 倍。这可能不是问题,但我能做些什么吗?
我预计磁盘访问可能是问题所在,因为该表并非一直在内存中。
EXPLAIN ANALYZE
SELECT SUM("value")
FROM "energy_energyentry"
WHERE
"prop_id"=82411
AND "timestamp">'2014-06-11'
AND "timestamp"<'2014-11-11'
;
Run Code Online (Sandbox Code Playgroud)
Run Code Online (Sandbox Code Playgroud)Aggregate (cost=214481.45..214481.46 rows=1 width=8) (actual time=51504.814..51504.814 rows=1 loops=1) -> Index Scan using energy_energyentry_prop_id_timestamp_idx on energy_energyentry (cost=0.00..214434.08 rows=18947 width=8) (actual time=136.030..51488.321 rows=13578 loops=1) Index Cond: ((prop_id = 82411) AND ("timestamp" > '2014-06-11 00:00:00+00'::timestamp with time zone) AND ("timestamp" < '2014-11-11 00:00:00+00'::timestamp with time zone)) Total runtime: 51504.841 ms
任何建议如何使这更快?
我也很好,只是听说我没有做任何奇怪的事情。
Erw*_*ter 15
您的表很大,跨越整个表的任何索引也是如此。假如说:
timestamp = now())我建议使用部分多列(覆盖!)索引:
CREATE INDEX ON energy_energyentry (prop_id, "timestamp", value)
WHERE "timestamp" >= '2014-01-01 0:0'; -- adapt to your needs
Run Code Online (Sandbox Code Playgroud)
只包含定期查询的时间范围。随着新条目的出现,有效性会随着时间的推移而恶化。不时重新创建索引。(您可能需要调整您的查询。)请参阅下面的链接答案。
最后一列值仅用于从中获取仅索引扫描。积极的 autovacuum 设置可能有助于保持可见性地图最新,就像@jjanes 已经提到的那样。
部分索引应该更容易适应 RAM 并在那里停留更长时间。
您可能需要WHERE在查询中包含此条件,以使规划器了解索引适用于查询,例如:
SELECT sum(value) AS sum_value
FROM energy_energyentry
WHERE prop_id = 82411
AND "timestamp" > '2014-06-11 0:0'
AND "timestamp" < '2014-11-11 0:0'
AND "timestamp" >= '2014-01-01 0:0'; -- seems redundant, but may be needed
Run Code Online (Sandbox Code Playgroud)
由于您的查询汇总了很多行 ( rows=13578),因此即使使用仅索引扫描,这也需要一些时间。不过,它不应该接近 50 秒。在任何中等体面的硬件上不到一秒钟。
相关(但忽略CLUSTERand FILLFACTOR,如果您可以从中获得仅索引扫描,则两者都无关紧要):
旁白:
由于您目前在 上有一个索引(prop_id, "timestamp"),因此在 上的额外索引的(prop_id)成本可能会超过其价值:
如果在 (prop_id, "timestamp","value") 上创建索引,则它可以使用仅索引扫描来计算值,而无需访问表。这可以节省大量随机磁盘访问。
为了获得最大的好处,您需要积极地对桌子进行吸尘。对于您希望有效支持仅索引扫描的仅插入表,默认的 autovac 设置不够激进。
| 归档时间: |
|
| 查看次数: |
21662 次 |
| 最近记录: |