【发布时间】:2018-09-26 06:56:32
【问题描述】:
我确实有两个相当大的表,我需要在它们之间进行日期范围连接。不幸的是,查询需要 12 多个小时。我正在使用在 docker 中运行的 postgresql 10.5,最大。 5GB 内存和多达 12 个 CPU 内核可用。
基本上,在左表中,我确实有一个设备 ID 和一个日期范围列表(从 = Timestamp,到 = ValidUntil)。然后我想加入右表,其中包含所有设备的测量值(传感器数据),以便我只获得位于日期范围之一(来自左表)内的传感器数据。查询:
select
A.*,
B."Timestamp" as "PressureTimestamp",
B."PropertyValue" as "Pressure"
from A
inner join B
on B."EquipmentId" = A."EquipmentId"
and B."Timestamp" >= A."Timestamp"
and B."Timestamp" < A."ValidUntil"
不幸的是,这个查询只使用了一个核心,这可能是它运行如此缓慢的原因。有没有办法重写查询以便并行化?
索引:
create index if not exists A_eq_timestamp_validUntil on public.A using btree ("EquipmentId", "Timestamp", "ValidUntil");
create index if not exists B_eq_timestamp on public.B using btree ("EquipmentId", "Timestamp");
表格:
-- contains 332,000 rows
CREATE TABLE A (
"EquipmentId" bigint,
"Timestamp" timestamp without time zone,
"ValidUntil" timestamp without time zone
)
WITH ( OIDS = FALSE )
-- contains 70,000,000 rows
CREATE TABLE B
(
"EquipmentId" bigint,
"Timestamp" timestamp without time zone,
"PropertyValue" double precision
)
WITH ( OIDS = FALSE )
执行计划(解释...输出):
Nested Loop (cost=176853.59..59023908.95 rows=941684055 width=48)
-> Bitmap Heap Scan on v2_pressure p (cost=176853.16..805789.35 rows=9448335 width=24)
Recheck Cond: ("EquipmentId" = 2956235)
-> Bitmap Index Scan on v2_pressure_eq (cost=0.00..174491.08 rows=9448335 width=0)
Index Cond: ("EquipmentId" = 2956235)"
-> Index Scan using v2_prs_eq_timestamp_validuntil on v2_prs prs (cost=0.42..5.16 rows=100 width=32)
Index Cond: (("EquipmentId" = 2956235) AND (p."Timestamp" >= "Timestamp") AND (p."Timestamp" < "ValidUntil"))
更新 1: 根据 cmets 修复了索引,这大大提高了性能
【问题讨论】:
-
您似乎在这些表上没有任何索引。在
b("Timestsamp")上试一试,在a("Timestamp", "ValidUntil")上试一试 -
无关,但是:你真的应该避免那些可怕的带引号的标识符。他们的麻烦比他们的价值要多得多
-
Postgres 通常只使用一个索引。您已经在三个不同的列上定义了三个单独的索引。您可能想尝试一个 composite 索引,该索引涉及连接中涉及的部分或全部列。
-
使用索引改善了看起来的情况(测试仍在运行),但它仍然只使用 1 个核心。有没有办法以某种方式编写查询,以便 pgsql 可以并行执行查询?
-
你可以尝试显式hash join,也许这有助于执行计划中的堆扫描。
标签: sql postgresql performance