【发布时间】:2021-01-16 06:54:51
【问题描述】:
我的 postgres 数据库(版本 11)中有下表:
CREATE TABLE instance
(
id bigserial,
period DATERANGE NOT NULL,
status TEXT NOT NULL, -- (wait, active, inactive, outdated)
position BIGINT NOT NULL,
CONSTRAINT instance_pk PRIMARY KEY (id),
CONSTRAINT instance_period_check CHECK (NOT isempty(period))
);
我需要从 java 代码中按批次大小 1000 更改按位置排序的实例的状态:
List<Instance> instances;
Long position = null;
do {
instances = dao.getInstancesBeforePeriod(fromStatus, position);
if (instances.isEmpty()) {
break;
}
processBatch(toStatus, instances);
position = instances.get(instances.size() - 1).getPosition();
} while (true);
dao.getInstancesBeforePeriod(fromStatus, position) if position == null 调用查询:
SELECT id, status, period, position
FROM instance
WHERE status = :status
AND upper(period) < now()
ORDER BY position
LIMIT 1000;
如果 position != null 调用查询:
SELECT id, status, period, position
FROM instance
WHERE status = :status
AND upper(period) < now()
AND position > :position
ORDER BY position
LIMIT 1000;
但是第一个查询命中/读取了太多共享块,因此查询失败并出现超时异常。 我该如何解决这个问题?
如果我要在实例表上添加索引会怎样:
create index concurrently instance_index_status_upper_period_position
on instance(status, upper(period), position)
但我希望索引保持实例按位置排序。是否可以?我是否应该通过在 where 子句中添加 position > 0 来更改第一个查询以使用此类索引?
第一个查询的解释分析结果:
我会欣赏任何想法。谢谢! :)
【问题讨论】:
-
你能发布慢查询的解释分析吗?另外,如果您想获取批次,为什么不使用游标?
-
请edit您的问题并添加使用
explain (analyze, buffers, format text)生成的execution plan(不是只是一个“简单”解释)为formatted text,并确保保留计划的缩进。粘贴文本,然后将```放在计划前一行和计划后一行。 -
upper(period)?那是指JANUARI而不是别的东西吗? -
在问题中,我分享了基于生产中实际表格的简化表格。我还生成了一些测试数据。我想,我不允许在这里分享生产代码。我可以说在生产中
Buffers: shared hit=175243 -
您没有太多的共享缓冲区命中。缓冲区命中意味着 Postgres 发现必要的数据已经在内存中,从而避免了物理 i/o。缓冲区命中比任何 i/o 操作都要快几个数量级。也许您从 LIMIT 子句中得到了错误的印象,但是,该子句仅在查询以其他方式解决后才应用。您的查询读取每一行,对它们进行排序,然后才应用 LIMIT。
标签: sql postgresql indexing