Ger*_*fer 4 postgresql configuration query-optimization postgresql-9.2 postgresql-performance
我有一个问题,感觉它需要花费更多的时间.这仅适用于给定参数集的第一个查询,因此在缓存时没有问题.
我不确定会发生什么,但是,考虑到设置和设置,我希望有人可以对几个问题有所了解,并提供一些有关如何加快查询速度的见解.该表格相当大,Postgres估计其中大约155963000(14 GB).
select ts, sum(amp) as total_amp, sum(230 * factor) as wh
from data_cbm_aggregation_15_min
where virtual_id in (1818) and ts between '2015-02-01 00:00:00' and '2015-03-31 23:59:59'
and deleted is null
group by ts
order by ts
Run Code Online (Sandbox Code Playgroud)
当我开始研究这个查询时花了大约15秒,经过一些更改后我已经达到了大约10秒,这对于像这样的简单查询似乎仍然很长.下面是结果explain analyze: http://explain.depesz.com/s/97V1.请注意GroupAggregate返回相同行数的原因是此示例仅virtual_id使用了一行,但可能会有更多行.
正在查询的表,它每15分钟插入一次值
CREATE TABLE data_cbm_aggregation_15_min (
virtual_id integer NOT NULL,
ts timestamp without time zone NOT NULL,
amp real,
recs smallint,
min_amp real,
max_amp real,
deleted boolean,
factor real DEFAULT 0.25,
min_amp_ts timestamp without time zone,
max_amp_ts timestamp without time zone
)
ALTER TABLE data_cbm_aggregation_15_min ALTER COLUMN virtual_id SET STATISTICS 1000;
ALTER TABLE data_cbm_aggregation_15_min ALTER COLUMN ts SET STATISTICS 1000;
Run Code Online (Sandbox Code Playgroud)
查询中使用的索引
CREATE UNIQUE INDEX idx_data_cbm_aggregation_15_min_virtual_id_ts
ON data_cbm_aggregation_15_min USING btree (virtual_id, ts DESC);
ALTER TABLE data_cbm_aggregation_15_min
CLUSTER ON idx_data_cbm_aggregation_15_min_virtual_id_ts;
Run Code Online (Sandbox Code Playgroud)
其他设置是默认设置.
default_statistics_target = 100
maintenance_work_mem = 2GB
effective_cache_size = 11GB
work_mem = 256MB
shared_buffers = 3840MB
random_page_cost = 1
Run Code Online (Sandbox Code Playgroud)
在您发布https://wiki.postgresql.org/wiki/Slow_Query_Questions之前,我一直在关注这些事情,结果更详细如下:
random_page_cost自索引扫描以来降低,虽然它看起来不太特别,但是当它random_page_cost更高时,它会尝试做的位图堆扫描前面几英里.virtual_id和ts列WHERE.更改后,查询计划程序的估计行数更接近实际行数.the idx_data_cbm_aggregation_15_min_virtual_id_ts索引上的聚类似乎没有太大变化,而不是我注意到的.VACUUM手动运行没有太大变化,我已经运行autovacuum所以这并不奇怪.REINDEX在索引上运行大大缩减了(差不多50%!)但它没有提高速度.SELECT ts, sum(amp) AS total_amp, sum(factor) * 230 AS wh
FROM data_cbm_aggregation_15_min
WHERE virtual_id = 1818
AND ts >= '2015-02-01 00:00'
AND ts < '2015-04-01 00:00'
AND deleted IS NULL
GROUP BY ts
ORDER BY ts;
Run Code Online (Sandbox Code Playgroud)
- 将总和乘以一次而不是乘以每个元素会更便宜:sum(230 * factor)sum(factor) * 230结果是相同的,即使是NULL值也是如此.
可能不正确.要包括2015年3月的所有内容,请使用提供的替代方案.无论如何ts between '2015-02-01 00:00:00' and '2015-03-31 23:59:59'BETWEEN被翻译ts >= lower AND ts <= upper.它总是略快拼出来.
只是一种不必要的复杂的说法virtual_id in (1818)virtual_id = 1818.
CREATE INDEX data_cbm_aggregation_15_min_special_idx
ON data_cbm_aggregation_15_min (virtual_id, ts, amp, factor)
WHERE deleted IS NULL;
Run Code Online (Sandbox Code Playgroud)
我在你的问题中没有看到DESC你的原始索引中的任何内容.虽然Index Scan Backward几乎和平原一样快Index Scan,但放弃修饰符仍然更好.
最重要的是,自Postgres 9.2以来,只有索引扫描.我附加的两个索引列(amp,factor)仅在您从中获得仅索引扫描时才有意义.
由于您显然对已删除的行不感兴趣,因此将其设为部分索引.只有在表格中有多个已删除的行时才需要付费.
如果您可以排除表的其他大部分,请添加更多条件 - 并记住在查询中重复条件(即使看起来多余),因此Postgres了解索引是适用的.
像这样重新排序表列将每行节省8个字节:
CREATE TABLE data_cbm_aggregation_15_min (
virtual_id integer NOT NULL,
recs smallint,
deleted boolean,
ts timestamp NOT NULL,
amp real,
min_amp real,
max_amp real,
factor real DEFAULT 0.25,
min_amp_ts timestamp,
max_amp_ts timestamp
);
Run Code Online (Sandbox Code Playgroud)
有关:
对于非常大的表,第一次查询调用可能实质上更昂贵,因为整个表不能被缓存.后续调用从填充的缓存中获利.Postgres缓存块,不一定是整个表.
还有一件事对于第一次通话很重要.由于Postgres的MVCC模型,它必须保持可见性信息.当自上次写入操作以来第一次读取表的页面时,Postgres会机会性地更新可见性信息,这可能会为第一次访问带来一些额外的成本(并为后续调用提供大量帮助).更多在手册中.关于dba.SE的相关回答:
SET STATISTICS 1000对于ts并且virtual_id是一个很好的想法,但效果在很大程度上通过设置无效random_page_cost = 1,这基本上强制对此查询进行索引扫描.
random_page_cost = 1正在告诉Postgres,随机访问与顺序访问一样便宜.这对于(几乎)完全驻留在缓存中的DB是有意义的.对于像你这样的巨大表格的数据库,这个设置似乎太极端了(即使它让Postgres支持所需的索引扫描).设置为random_page_cost = 1.1或可能更高.
对于您呈现的查询的第一次调用,位图索引扫描通常是一个很好的计划 - 用于在表中随机分布的数据.由于您就像对此查询所需的那样对表进行聚类,因此索引扫描更有效.问题是:你的桌子会保持聚集状态吗?
您的设置work_mem和其他资源,取决于你有多少RAM,您的磁盘的速度,对访问模式,你通常有多少并发连接有,是什么在服务器上的其他程序争夺资源等work_mem = 256MB似乎过高.对于呈现的查询,您不需要那么多.将其设置为高可能实际上会损害性能,因为它减少了可用于缓存的RAM.
REINDEX之后不会冗余CLUSTER,因为无论如何都会重新创建所有索引.您必须REINDEX 在群集之前运行,或者您在表上拥有大量写入权限才能再次获得如此大的膨胀.
升级到Postgres 9.4(或即将推出的9.5,目前为alpha).版本9.2现在已经有3年了,最新版本已经获得了很多改进.
该查询计划表明,没有什么实际汇总.rows=4,117从索引中读取并rows=4,117保留GroupAggregate.看起来行ts已经是唯一的?然后你可以完全删除聚合并使它变得简单SELECT......
如果这只是一个误导性的EXPLAIN输出,并且您通常输出的行数比读取的少得多,那么MATERIALIZED VIEW索引为on ts将是另一种选择.特别是与Postgres 9.4相结合,介绍REFRESH MATERIALIZED VIEW CONCURRENTLY.
| 归档时间: |
|
| 查看次数: |
1202 次 |
| 最近记录: |