这与我发布的其他2个问题有关(听起来我应该将其作为新问题发布)-反馈有所帮助,但我认为下次我需要插入数据时,也会再次遇到相同的问题。事情仍在缓慢进行,这迫使我暂时删除了一些较旧的数据,因此我查询的表中只剩下2个月的时间。
Indexing strategy for different combinations of WHERE clauses incl. text patterns
How to get date_part query to hit index?
这次提供更多细节-希望它将有助于查明问题所在:
最大表的架构:
-- Table Definition ----------------------------------------------
CREATE TABLE reportimpression (
datelocal timestamp without time zone,
devicename text,
network text,
sitecode text,
advertisername text,
mediafilename text,
gender text,
agegroup text,
views integer,
impressions integer,
dwelltime numeric
);
-- Indices -------------------------------------------------------
CREATE INDEX reportimpression_feb2019_index ON reportimpression(datelocal timestamp_ops) WHERE datelocal >= '2019-02-01 00:00:00'::timestamp without time zone AND datelocal < '2019-03-01 00:00:00'::timestamp without time zone;
CREATE INDEX reportimpression_mar2019_index ON reportimpression(datelocal timestamp_ops) WHERE datelocal >= '2019-03-01 00:00:00'::timestamp without time zone AND datelocal < '2019-04-01 00:00:00'::timestamp without time zone;
CREATE INDEX reportimpression_jan2019_index ON reportimpression(datelocal timestamp_ops) WHERE datelocal >= '2019-01-01 00:00:00'::timestamp without time zone AND datelocal < '2019-02-01 00:00:00'::timestamp without time zone;
慢查询:
SELECT
date_part('hour', datelocal) AS hour,
SUM(CASE WHEN gender = 'male' THEN views ELSE 0 END) AS male,
SUM(CASE WHEN gender = 'female' THEN views ELSE 0 END) AS female
FROM reportimpression
WHERE
datelocal >= '3-1-2019' AND
datelocal < '4-1-2019'
GROUP BY date_part('hour', datelocal)
ORDER BY date_part('hour', datelocal)
此查询中的日期范围通常为整个月(它接受来自基于Web的报告的用户输入)-如您所见,我尝试为每个月的数据创建索引。这很有帮助,但据我所知,除非查询最近已运行(将结果放入缓存中),否则仍可能需要一分钟才能运行。
说明分析结果:
Finalize GroupAggregate (cost=1035890.38..1035897.86 rows=1361 width=24) (actual time=3536.089..3536.108 rows=24 loops=1)
Group Key: (date_part('hour'::text, datelocal))
-> Sort (cost=1035890.38..1035891.06 rows=1361 width=24) (actual time=3536.083..3536.087 rows=48 loops=1)
Sort Key: (date_part('hour'::text, datelocal))
Sort Method: quicksort Memory: 28kB
-> Gather (cost=1035735.34..1035876.21 rows=1361 width=24) (actual time=3535.926..3579.818 rows=48 loops=1)
Workers Planned: 1
Workers Launched: 1
-> Partial HashAggregate (cost=1034735.34..1034740.11 rows=1361 width=24) (actual time=3532.917..3532.933 rows=24 loops=2)
Group Key: date_part('hour'::text, datelocal)
-> Parallel Index Scan using reportimpression_mar2019_index on reportimpression (cost=0.09..1026482.42 rows=3301168 width=17) (actual time=0.045..2132.174 rows=2801158 loops=2)
Planning time: 0.517 ms
Execution time: 3579.965 ms
我认为一千万条记录不会处理太多,尤其是考虑到我最近提高了PG规划以投入大量资源,因此我认为问题仍然是我的索引或查询效率都不高。
答案 0 :(得分:2)
您的执行计划似乎做对了。
可以按照效果从高到低的顺序进行改进:
使用预先汇总数据的物化视图
不要使用托管数据库,请使用具有良好本地存储和大量RAM的自己的Iron。
仅使用一个索引而不是多个分区索引。这主要不是性能建议(除非您有很多索引,否则查询可能不会明显变慢),但是它将减轻管理负担。
答案 1 :(得分:2)
materialized view 是您概述的方法。查询过去几个月的只读数据无需刷新即可。如果您还需要涵盖当月的情况,则可能需要特殊设置。
基础查询仍然可以从索引中受益,您可能会遵循两个指示:
首先,partial indexes就像您现在不会在您的方案中购买太多,不值得。如果您收集了更多个月的数据,并且主要是按月查询(并按月添加/删除行),table partitioning可能是个好主意,那么您的索引也会自动分区。不过,我会考虑使用Postgres 11或即将推出的Postgres 12。)
如果您的行很宽,请创建一个允许 index-only scans 的索引。喜欢:
CREATE INDEX reportimpression_covering_idx ON reportimpression(datelocal, views, gender);
相关:
或在Postgres 11或更高版本中另外INCLUDE
列:
CREATE INDEX reportimpression_covering_idx ON reportimpression(datelocal) INCLUDE (views, gender);
其他,如果您的行按datelocal
进行物理排序,请考虑使用 BRIN index 。对于您的情况,它非常小,可能与B树索引一样快。 (但是太小了,它将使缓存变得更加容易,并且不会过多地推送其他数据。)
CREATE INDEX reportimpression_brin_idx ON reportimpression USING BRIN (datelocal);
您可能对CLUSTER
或pg_repack
进行物理排序的表行感兴趣。 pg_repack
可以做到这一点而无需在表上排他锁,甚至没有btree索引(CLUSTER
都必须)。但这是Postgres的标准发行版未附带的附加模块。
相关: