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 WHERE
klauzuli, 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?
Odpowiedzi:
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.
źródło