Postgresql仅索引扫描无法在Group By上正常工作
我有一张像这样的桌子:Postgresql仅索引扫描无法在Group By上正常工作,postgresql,indexing,query-performance,Postgresql,Indexing,Query Performance,我有一张像这样的桌子: 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),
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
);
我的表大小是1786MB(索引除外)。在这里,我创建了如下索引:
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;
我的简单查询如下所示:
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;
选择
事件名称,
最大值(上次事件时间)
从摘要s
其中s.user_id=?和s.product_id=?和s.product_type=?
和s.last_event_time>'2020-03-01'和s.last_event_time<'2020-03-25'
按事件名称分组;
当我解释它时,它看起来像
HashAggregate(成本=93.82..96.41行=259宽度=25)(实际时间=9187.533..9187.536行=10个循环=1)
组键:事件名称
缓冲区:共享命中=70898读=10579脏=22650
I/O定时:读取=3876.367
->仅使用摘要s上的“idx_as_type_usr_productId_eventTime”进行索引扫描(成本=0.56..92.36行=292宽度=25)(实际时间=0.485..9153.812行=87322循环=1)
索引条件:((产品类型=2)和(产品id=?)和(产品id=?)和(上次事件时间>'2020-03-01 00:00:00':无时区时间戳)和(上次事件时间<'2020-03-25 00:00:00':无时区时间戳))
堆取数:35967
缓冲区:共享命中=70898读=10579脏=22650
I/O定时:读取=3876.367
计划时间:0.452毫秒
执行时间:9187.583毫秒
在这里,一切看起来都很好。但是当我执行它的时候,它需要超过10秒,有时需要超过30秒
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';
选择
事件名称,
上次活动时间
从摘要s
其中s.user_id=?和s.product_id=?和s.product_type=?
和s.last_event_time>'2020-03-01'和s.last_event_time<'2020-03-25';
无需解释-分组方式:
仅使用摘要s上的“idx_as_type_usr_productId_eventTime”进行索引扫描(成本=0.56..92.36行=292宽度=25)(实际时间=0.023..79.138行=87305循环=1)
索引条件:((产品类型=?)和(用户id=?)和(产品id=?)和(上次事件时间>'2020-03-01 00:00:00'::无时区时间戳)和(上次事件时间<'2020-03-25 00:00:00'::无时区时间戳))
堆取数:22949
缓冲区:共享命中=37780读取=12143脏化=15156
I/O定时:读取=4418.930
计划时间:0.639毫秒
执行时间:4625.213毫秒
有几个问题:
- PostgreSQL必须设置提示位,这会弄脏页面并导致写入
- PostgreSQL必须从磁盘获取表行以获取它们的可见性
- PostgreSQL必须扫描80000页才能获得87000行,因此索引必须完全膨胀
VACUUM summary;
这总是一个好主意后,大量装载,和膨胀可以治愈
REINDEX INDEX "idx_as_type_usr_productId_eventTime";
有几个问题:
- PostgreSQL必须设置提示位,这会弄脏页面并导致写入
- PostgreSQL必须从磁盘获取表行以获取它们的可见性
- PostgreSQL必须扫描80000页才能获得87000行,因此索引必须完全膨胀
VACUUM summary;
这总是一个好主意后,大量装载,和膨胀可以治愈
REINDEX INDEX "idx_as_type_usr_productId_eventTime";
请以文本格式显示解释(分析、缓冲区)和。JSON格式适合机器阅读,但我们不是机器。更好的是,如果还没有开始,先打开track\u io\u timing。请对没有分组依据的查询执行相同的操作,因为您也询问了该查询。该查询与计划不匹配<代码>(上次事件时间>'2020-03-01 00:00:00':无时区的时间戳)和(上次事件时间<'2020-03-25 00:00:00':无时区的时间戳))“不在查询中。请提出一个前后一致的问题。总是从公开你的Postgres版本开始。杰夫对文本格式的看法。@jjanes和Erwin;问题已按您所说的方式编辑。@a_horse_,没有固定名称。请以文本格式显示解释(分析、缓冲区)。JSON格式适合机器阅读,但我们不是机器。更好的是,如果还没有开始,先打开track\u io\u timing。请对没有分组依据的查询执行相同的操作,因为您也询问了该查询。该查询与计划不匹配<代码>(上次事件时间>'2020-03-01 00:00:00':无时区的时间戳)和(上次事件时间<'2020-03-25 00:00:00':无时区的时间戳))“不在查询中。请提出一个前后一致的问题。总是从公开你的Postgres版本开始。杰夫对文本格式的看法。@jjanes和Erwin;问题已按您所说的编辑。@a_horse_,没有固定名称。Laurenz,谢谢您的回答。我知道这与数据库缓存有关,因为我按顺序获取了它们。因此,我再次更新了问题。此时,我在两次查询之间留出15分钟的时间获取它们。这里我的主要问题不是group by和non group by之间的差异。我的主要问题是,;只有500行需要扫描,而此扫描是仅索引扫描,因此为什么提取时间如此长?我已根据更改后的问题调整了答案。但此表每秒至少有30次插入/更新操作。那么我应该一直重新编制索引吗?它是否适用于解决方案?这是您问题的根本原因。调整自动真空并使用热更新。但这是另一个问题的材料。劳伦兹,谢谢你的回答。我知道这与数据库缓存有关,因为我按顺序获取了它们。因此,我再次更新了问题。此时,我在两次查询之间留出15分钟的时间获取它们。这里我的主要问题不是group by和non group by之间的差异。