仅对 Postgresql 索引进行扫描无法在 Group By 上正常工作
Postgresql Index Only Scan Doesnt Properly Work On Group By
我有一个 table 喜欢:
CREATE TABLE summary
(
id serial NOT NULL,
user_id bigint NOT NULL,
country character varying(5),
product_id bigint NOT NULL,
category_id bigint NOT NULL,
text_id bigint NOT NULL,
text character varying(255),
product_type integer NOT NULL,
event_name character varying(255),
report_date date NOT NULL,
currency character varying(5),
revenue double precision,
last_event_time timestamp
);
我的 table 大小是 1786 MB(索引除外)。在这里,我创建了如下索引:
CREATE INDEX "idx_as_type_usr_productId_eventTime"
ON summary USING btree
(product_type, user_id, product_id, last_event_time)
INCLUDE(event_name);
我的简单查询如下所示:
select
event_name,
max(last_event_time)
from summary s
where s.user_id = ? and s.product_id = ? and s.product_type = ?
and s.last_event_time > '2020-03-01' and s.last_event_time < '2020-03-25'
group by event_name;
我解释的时候,好像是;
HashAggregate (cost=93.82..96.41 rows=259 width=25) (actual time=9187.533..9187.536 rows=10 loops=1)
Group Key: event_name
Buffers: shared hit=70898 read=10579 dirtied=22650
I/O Timings: read=3876.367
-> Index Only Scan using "idx_as_type_usr_productId_eventTime" on summary s (cost=0.56..92.36 rows=292 width=25) (actual time=0.485..9153.812 rows=87322 loops=1)
Index Cond: ((product_type = 2) AND (product_id = ?) AND (product_id = ?) AND (last_event_time > '2020-03-01 00:00:00'::timestamp without time zone) AND (last_event_time < '2020-03-25 00:00:00'::timestamp without time zone))
Heap Fetches: 35967
Buffers: shared hit=70898 read=10579 dirtied=22650
I/O Timings: read=3876.367
Planning Time: 0.452 ms
Execution Time: 9187.583 ms
在这里,一切看起来都很好。但是我执行的时候,10多秒,有的时候30多秒。
- 在这里,如果我不使用 Group By 执行它,它 returns 会很快 returns 不到 2 秒。 Group By 能起到什么作用? select 部分太小了(大约 500 行)。
- 此 table 具有每秒 30 次的 insert/update 次操作。这可能与这个索引问题有关吗?
更新:
查询不带 - GroupBy:
select
event_name,
last_event_time
from summary s
where s.user_id = ? and s.product_id = ? and s.product_type = ?
and s.last_event_time > '2020-03-01' and s.last_event_time < '2020-03-25';
不解释 - 分组依据:
Index Only Scan using "idx_as_type_usr_productId_eventTime" on summary s (cost=0.56..92.36 rows=292 width=25) (actual time=0.023..79.138 rows=87305 loops=1)
Index Cond: ((product_type = ?) AND (user_id = ?) AND (product_id = ?) AND (last_event_time > '2020-03-01 00:00:00'::timestamp without time zone) AND (last_event_time < '2020-03-25 00:00:00'::timestamp without time zone))
Heap Fetches: 22949
Buffers: shared hit=37780 read=12143 dirtied=15156
I/O Timings: read=4418.930
Planning Time: 0.639 ms
Execution Time: 4625.213 ms
有几个问题:
PostgreSQL 必须设置 提示位,这会弄脏页面并导致写入。
PostgreSQL 必须从磁盘中获取 table 行以获取它们的可见性。
PostgreSQL 必须扫描 80000 页才能获得 87000 行,因此索引必须完全膨胀。
前两个可以由运行
处理
VACUUM summary;
这在大量加载后总是一个好主意,可以通过
治愈臃肿
REINDEX INDEX "idx_as_type_usr_productId_eventTime";
我有一个 table 喜欢:
CREATE TABLE summary
(
id serial NOT NULL,
user_id bigint NOT NULL,
country character varying(5),
product_id bigint NOT NULL,
category_id bigint NOT NULL,
text_id bigint NOT NULL,
text character varying(255),
product_type integer NOT NULL,
event_name character varying(255),
report_date date NOT NULL,
currency character varying(5),
revenue double precision,
last_event_time timestamp
);
我的 table 大小是 1786 MB(索引除外)。在这里,我创建了如下索引:
CREATE INDEX "idx_as_type_usr_productId_eventTime"
ON summary USING btree
(product_type, user_id, product_id, last_event_time)
INCLUDE(event_name);
我的简单查询如下所示:
select
event_name,
max(last_event_time)
from summary s
where s.user_id = ? and s.product_id = ? and s.product_type = ?
and s.last_event_time > '2020-03-01' and s.last_event_time < '2020-03-25'
group by event_name;
我解释的时候,好像是;
HashAggregate (cost=93.82..96.41 rows=259 width=25) (actual time=9187.533..9187.536 rows=10 loops=1)
Group Key: event_name
Buffers: shared hit=70898 read=10579 dirtied=22650
I/O Timings: read=3876.367
-> Index Only Scan using "idx_as_type_usr_productId_eventTime" on summary s (cost=0.56..92.36 rows=292 width=25) (actual time=0.485..9153.812 rows=87322 loops=1)
Index Cond: ((product_type = 2) AND (product_id = ?) AND (product_id = ?) AND (last_event_time > '2020-03-01 00:00:00'::timestamp without time zone) AND (last_event_time < '2020-03-25 00:00:00'::timestamp without time zone))
Heap Fetches: 35967
Buffers: shared hit=70898 read=10579 dirtied=22650
I/O Timings: read=3876.367
Planning Time: 0.452 ms
Execution Time: 9187.583 ms
在这里,一切看起来都很好。但是我执行的时候,10多秒,有的时候30多秒。
- 在这里,如果我不使用 Group By 执行它,它 returns 会很快 returns 不到 2 秒。 Group By 能起到什么作用? select 部分太小了(大约 500 行)。
- 此 table 具有每秒 30 次的 insert/update 次操作。这可能与这个索引问题有关吗?
更新:
查询不带 - GroupBy:
select
event_name,
last_event_time
from summary s
where s.user_id = ? and s.product_id = ? and s.product_type = ?
and s.last_event_time > '2020-03-01' and s.last_event_time < '2020-03-25';
不解释 - 分组依据:
Index Only Scan using "idx_as_type_usr_productId_eventTime" on summary s (cost=0.56..92.36 rows=292 width=25) (actual time=0.023..79.138 rows=87305 loops=1)
Index Cond: ((product_type = ?) AND (user_id = ?) AND (product_id = ?) AND (last_event_time > '2020-03-01 00:00:00'::timestamp without time zone) AND (last_event_time < '2020-03-25 00:00:00'::timestamp without time zone))
Heap Fetches: 22949
Buffers: shared hit=37780 read=12143 dirtied=15156
I/O Timings: read=4418.930
Planning Time: 0.639 ms
Execution Time: 4625.213 ms
有几个问题:
PostgreSQL 必须设置 提示位,这会弄脏页面并导致写入。
PostgreSQL 必须从磁盘中获取 table 行以获取它们的可见性。
PostgreSQL 必须扫描 80000 页才能获得 87000 行,因此索引必须完全膨胀。
前两个可以由运行
处理VACUUM summary;
这在大量加载后总是一个好主意,可以通过
治愈臃肿REINDEX INDEX "idx_as_type_usr_productId_eventTime";