postgresql - объединение двух больших таблиц занимает очень много времени - PullRequest
0 голосов
/ 26 сентября 2018

У меня есть две довольно большие таблицы, и мне нужно сделать соединение диапазона дат между ними.К сожалению, запрос занимает более 12 часов.Я использую Postgresql 10,5 работает в Docker с макс.Доступно 5 ГБ оперативной памяти и до 12 процессорных ядер.

В основном в левой таблице у меня есть идентификатор оборудования и список диапазонов дат (от = 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: Исправлены индексы, согласно комментариям, что улучшило производительность aсерия

Ответы [ 2 ]

0 голосов
/ 26 сентября 2018
-- \i tmp.sql

CREATE TABLE A
        ( equipmentid bigint NOT NULL
        , ztimestamp timestamp without time zone NOT NULL
        , validuntil timestamp without time zone NOT NULL
        , PRIMARY KEY (equipmentid,ztimestamp)
        , UNIQUE (equipmentid,validuntil) -- mustbeunique, since the intervals dont overlap
        ) ;

-- contains 70,000,000 rows
CREATE TABLE B
        ( equipmentid bigint NOT NULL
        , ztimestamp timestamp without time zone NOT NULL
        , propertyvalue double precision
        , PRIMARY KEY (equipmentid,ztimestamp)
        ) ;

INSERT INTO B(equipmentid,ztimestamp,propertyvalue)
SELECT i,t, random()
FROM generate_series(1,1000) i
CROSS JOIN generate_series('2018-09-01','2018-09-30','1day'::interval) t
        ;


INSERT INTO A(equipmentid,ztimestamp,validuntil)
SELECT equipmentid,ztimestamp, ztimestamp+ '7 days'::interval
FROM B
WHERE date_part('dow', ztimestamp) =0
        ;

ANALYZE A;
ANALYZE B;

EXPLAIN
SELECT
    A.*,
    B.ztimestamp AS pressuretimestamp,
    B.propertyvalue AS pressure
FROM A
INNER JOIN B
    ON  B.equipmentid =  A.equipmentid
    AND B.ztimestamp   >= A.ztimestamp
    AND B.ztimestamp   <  A.validuntil
    WHERE A.equipmentid=333 -- I added this, the plan in the question also has a r estriction on Id
        ;

И полученный план:


SET
ANALYZE
ANALYZE
                                                 QUERY PLAN                                                 
------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.34..21.26 rows=17 width=40)
   ->  Index Scan using a_equipmentid_validuntil_key on a  (cost=0.17..4.34 rows=5 width=24)
         Index Cond: (equipmentid = 333)
   ->  Index Scan using b_pkey on b  (cost=0.17..3.37 rows=3 width=24)
         Index Cond: ((equipmentid = 333) AND (ztimestamp >= a.ztimestamp) AND (ztimestamp < a.validuntil))
(5 rowSET

То есть при моем текущем значении random_page_cost=1.1;

После установки на 4.0Я получаю тот же план, что и ОП:


SET
                                                                     QUERY PLAN                                                                     
----------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=35.13..54561.69 rows=1416136 width=40) (actual time=1.391..1862.275 rows=225540 loops=1)
   ->  Bitmap Heap Scan on aa2  (cost=34.71..223.52 rows=1345 width=24) (actual time=1.173..5.223 rows=1345 loops=1)
         Recheck Cond: (equipmentid = 5)
         Heap Blocks: exact=9
         ->  Bitmap Index Scan on aa2_equipmentid_validuntil_key  (cost=0.00..34.38 rows=1345 width=0) (actual time=1.047..1.048 rows=1345 loops=1)
               Index Cond: (equipmentid = 5)
   ->  Index Scan using bb2_pkey on bb2  (cost=0.42..29.87 rows=1053 width=24) (actual time=0.109..0.757 rows=168 loops=1345)
         Index Cond: ((equipmentid = 5) AND (ztimestamp >= aa2.ztimestamp) AND (ztimestamp < aa2.validuntil))
 Planning Time: 3.167 ms
 Execution Time: 2168.967 ms
(10 rows)
0 голосов
/ 26 сентября 2018

Корректировка индекса - это первый способ исправить медлительность, но это поможет только в некоторой степени.Учитывая, что ваши столы большие, я бы рекомендовал попробовать Postgres Partition .Он имеет некоторую встроенную поддержку от postgres.

Но вам нужно иметь некоторые критерии фильтрации / разбиения.Я не вижу ни одного предложения where в вашем запросе, поэтому не могу предложить.Может быть, вы можете попробовать equipmentId.Это также может помочь в достижении параллелизма.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...