Обмеження розділу не використовується для приєднання таблиць, розділених часовою міткою


11

Я маю структуру таблиці з розділеними на зразок:

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);
....

І так далі. Кожна таблиця має приблизно 20М рядків.

Якщо я запитую зразок датчиків і зразок часових позначок у WHEREпункті, план запитів показує, що обираються правильні таблиці та використовуються індекси, наприклад:

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' ;

Однак якщо я використовую CTE або поміщаю значення часових позначок у таблицю (не показано, навіть із індексами у тимчасовій таблиці).

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)
)

Щось подібне нижче

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

Виконує сканування індексу на кожній таблиці. Що все ще відносно швидко, але зі збільшенням складності запитів, це може перетворитись на послідовне сканування, яке в кінцевому підсумку буде дуже повільним для отримання ~ 40К рядків з обмеженого підмножини розділених таблиць (4-5 з 50).

Я стурбований тим , що - щось на зразок цього є проблемою.

Для нетривіальних виразів вам потрібно повторити більш-менш дослівно умову в запитах, щоб зрозуміти, що планувальник запитів Postgres розуміє, що він може покладатися на обмеження CHECK. Навіть якщо це здасться зайвим!

Як я можу покращити структуру розділів та запитів, щоб зменшити ймовірність запуску сканування послідовностей для всіх моїх даних?


1
чудове запитання - але було б ще краще, якщо ви вставите результати ПОЯСНЕННЯ (АНАЛІЗ, БУФЕРИ)
filiprem

Відповіді:


1

Виключення на основі обмежень [CBE] виконується на ранній стадії планування запитів, одразу після того, як запит буде проаналізований, відображений на фактичні відносини та переписаний. ( внутрішні місця , етап планування / оптимізатора)

Планувальник не може приймати будь-який вміст таблиці "sensor_sample".

Отже, якщо у запиті у вас немає твердо кодованих значень, планувальник не виключає "розділів".

Я думаю, що відбувається з варіантом CTE ... планувальник обмежений, оскільки ви використовуєте TABLESAMPLE, і весь підзапит може трактуватися як мінливий, навіть якщо літерали в підзапиті є статичними. ( це лише здогадка, я не знаю коду планувальника )

Зі свого боку, індексне сканування з негативним результатом надзвичайно швидко. (максимум сканування на одній сторінці!), тому якщо у вас більше 10000 розділів, я б не турбувався.

Отже, щоб відповісти на ваше запитання безпосередньо:

  • Ви не можете значно покращити цю структуру даних.

  • Щодо сканування індексів - вони дешеві;

  • Що стосується послідовних сканувань - їх уникають, коли це можливо, як ви бачите на власних прикладах.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.