Ograniczenie partycji nie jest używane w przypadku sprzężeń obejmujących tabele podzielone według datownika

11

Mam strukturę tabeli podzielonej na partycje, taką jak:

CREATE TABLE measurements (
    sensor_id bigint,
    tx timestamp,
    measurement int
);

CREATE TABLE measurements_201201(
    CHECK (tx >= '2012-01-01 00:00:00'::timestamp without time zone 
       AND tx < ('2012-01-01 00:00:00'::timestamp without time zone + '1 mon'::interval))    
)INHERITS (measurements);
CREATE INDEX ON measurements_201201(sensor_id);
CREATE INDEX ON measurements_201201(tx);
CREATE INDEX ON measurements_201201(sensor_id, tx);
....

I tak dalej. Każda tabela ma około 20 milionów wierszy.

Jeśli zapytam o próbkę czujników i próbkę znaczników czasu w WHEREklauzuli, plan zapytań pokazuje prawidłowe wybrane tabele i używane indeksy, np .:

SELECT *
FROM measurements
INNER JOIN sensors TABLESAMPLE BERNOULLI (0.01) USING (sensor_id)
WHERE tx BETWEEN '2015-01-04 05:00' AND '2015-01-04 06:00' 
    OR tx BETWEEN '2015-02-04 05:00' AND '2015-02-04 06:00' 
    OR tx BETWEEN '2014-03-05 05:00' AND '2014-04-07 06:00' ;

Jeśli jednak użyję CTE lub wstawię wartości znaczników czasu do tabeli (nie pokazano, nawet z indeksami w tabeli tymczasowej).

WITH sensor_sample AS(
    SELECT sensor_id, start_ts, end_ts
    FROM sensors TABLESAMPLE BERNOULLI (0.01)
    CROSS JOIN (VALUES (TIMESTAMP '2015-01-04 05:00', TIMESTAMP '2015-01-04 06:00'),
        (TIMESTAMP '2015-02-04 05:00', TIMESTAMP '2015-02-04 06:00'),
        (TIMESTAMP  '2014-03-05 05:00', '2014-04-07 06:00') ) tstamps(start_ts, end_ts)
)

Coś jak poniżej

SET constraint_exclusion = on;
SELECT * FROM measurements
INNER JOIN sensor_sample USING (sensor_id)
WHERE tx BETWEEN start_ts AND end_ts

Wykonuje skanowanie indeksu na każdym stole. Co wciąż jest względnie szybkie, ale wraz ze wzrostem złożoności zapytań, może to przekształcić się w skanowanie sekwencji, co w rezultacie będzie bardzo powolne w pobieraniu ~ 40 000 wierszy z ograniczonego podzbioru tabel podzielonych na partycje (4-5 z 50).

Martwię się, że coś w tym jest problem.

W przypadku wyrażeń nietrywialnych musisz powtórzyć mniej lub bardziej dosłownie warunek w zapytaniach, aby planista zapytań Postgres zrozumiał, że może polegać na ograniczeniu CHECK. Nawet jeśli wydaje się to zbędne!

Jak mogę ulepszyć partycjonowanie i strukturę zapytań, aby zmniejszyć prawdopodobieństwo uruchamiania skanowania sekwencji na wszystkich moich danych?

Rafael
źródło
1
świetne pytanie - ale byłoby jeszcze lepiej wkleić wyniki
WYJAŚNIENIA

Odpowiedzi:

1

Wyłączenie oparte na ograniczeniach [CBE] jest wykonywane na wczesnym etapie planowania zapytania, zaraz po jego przeanalizowaniu, odwzorowaniu na rzeczywiste relacje i przepisaniu. (elementy wewnętrzne , etap planowania / optymalizacji)

Planista nie może zakładać żadnej zawartości tabeli „sensor_sample”.

Więc jeśli nie masz wartości zakodowanych w zapytaniu, planista nie wykluczy „partycji”.

Chyba co dzieje się z wariantem CTE ... planista jest ograniczony, ponieważ używasz TABLESAMPLE, a całe podzapytanie może być traktowane jako zmienne, nawet jeśli literały w podzapytaniu są statyczne. ( tak sądzę, nie jestem ekspertem od kodu planisty )

Z drugiej strony, skanowanie indeksu z wynikiem ujemnym jest niezwykle szybkie. (skanowanie maksymalnie jednej strony!), więc jeśli nie masz ponad 10000 partycji, nie zawracałbym sobie głowy.

Tak więc, aby bezpośrednio odpowiedzieć na twoje pytanie:

  • Nie można znacznie poprawić tej struktury danych.

  • Skanowanie indeksu Regardin - są tanie;

  • Jeśli chodzi o sekwencyjne skany - są one unikane, gdy jest to możliwe, jak widać na własnych przykładach.

filiprem
źródło