Ограничение разделения не используется для объединений с таблицами, разделенными по метке времени

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. Даже если это кажется излишним!

Как я могу улучшить разбиение и структуру запросов, чтобы уменьшить вероятность выполнения seq-сканирования всех моих данных?

Рафаэль
источник
1
отличный вопрос - но было бы еще лучше, если бы вы вставили результаты EXPLAIN (ANALYZE, BUFFERS)
filiprem

Ответы:

1

Исключение на основе ограничений [CBE] выполняется на ранней стадии планирования запроса, сразу после того, как запрос проанализирован, сопоставлен с фактическими отношениями и переписан. ( внутренняя часть , этап Planner / Optimizer)

Планировщик не может принять какое-либо содержимое таблицы «sensor_sample».

Поэтому, если в запросе нет жестко заданных значений, планировщик не исключит «разделы».

Я предполагаю, что происходит с вариантом CTE ... планировщик ограничен, потому что вы используете TABLESAMPLE, и весь подзапрос может рассматриваться как изменчивый, даже если литералы в подзапросе являются статическими. ( это только мое предположение, я не эксперт в коде планировщика )

С другой стороны, индексное сканирование с отрицательным результатом является невероятно быстрым. (самое большее сканирование одной страницы!), поэтому, если у вас нет более 10000 разделов, я бы не стал беспокоиться.

Итак, чтобы ответить на ваш вопрос напрямую:

  • Вы не можете улучшить эту структуру данных намного больше.

  • Сканирование индекса Regardin - они дешевые;

  • Что касается последовательных сканирований - их по возможности избегают, как вы видите на своих примерах.

filiprem
источник