2010-02-10 2 views
10

Я только что изменил мою базу данных, чтобы использовать partitioning в Postgres 8.2. Теперь у меня проблема с выполнением запросов:Эффективный запрос многораздельной таблицы Postgres

SELECT * 
FROM my_table 
WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
ORDER BY id DESC 
LIMIT 100; 

В таблице 45 миллионов строк. Перед разделением это будет использовать обратное сканирование индекса и остановить, как только он достигнет предела.

После разделения (по диапазонам time_stamp) Postgres выполняет полное сканирование индекса главной таблицы и соответствующего раздела и объединяет результаты, сортирует их, затем применяет лимит. Это происходит слишком долго.

я могу это исправить с:

SELECT * FROM (
    SELECT * 
    FROM my_table_part_a 
    WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
    ORDER BY id DESC 
    LIMIT 100) t 
UNION ALL 
SELECT * FROM (
    SELECT * 
    FROM my_table_part_b 
    WHERE time_stamp >= '2010-02-10' and time_stamp < '2010-02-11' 
    ORDER BY id DESC 
    LIMIT 100) t 
UNION ALL 
    ... and so on ... 
ORDER BY id DESC 
LIMIT 100 

Это работает быстро. Разделы, в которых метки времени находятся вне диапазона, даже не включены в план запроса.

Мой вопрос: есть ли какой-либо намек или синтаксис, который я могу использовать в Postgres 8.2, чтобы предотвратить запрос от планировщика полной таблицы, но все же используя простой синтаксис, который относится только к главной таблице?

В принципе, могу ли я избежать боли при динамическом построении большого запроса UNION по каждому разделу, который в настоящее время определен?

EDIT: Я constraint_exclusion включены (спасибо @Vinko Vrsalovic)

+1

8.2? действительно? Прежде чем делать что-либо еще, вы должны рассмотреть возможность перехода на поддерживаемую (и текущую) версию Postgres (9.2 является текущей) –

ответ

3

Вы пробовали Constraint отчуждение (раздел 5.9.4 в документе вы связаны с)

Constraint исключение запрос метод оптимизации, который улучшает производительность для разбитых на разделы таблиц , описанных выше, как описано . В качестве примера:

SET constraint_exclusion = on; 
SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01'; 

Без ограничений исключения, приведенный выше запрос будет сканировать каждый из разделов таблицы измерений. При включении ограничения исключение, планировщик будет изучить трудности каждого раздела и попытаться доказать, что раздел не должен быть проверен, так как он не может содержать ни одной строки, отвечающие запрос, где положение. Когда планировщик может это доказать, он не включает раздел из плана запроса.

Вы можете использовать команду EXPLAIN, чтобы показать разницу между планом с constraint_exclusion на и план с приподнятым.

+0

Да, у меня включено ограничение исключения. К сожалению, основная таблица (которая всегда пуста) всегда включена в запрос, так как невозможно применить к ней ограничение CHECK (по крайней мере, в 8.2). Это означает, что в запросе всегда есть как минимум две таблицы –

4

У меня была аналогичная проблема, что я смог исправить условия литья в ГДЕ. EG: (предполагается, что столбец time_stamp является timestamptz типа)

WHERE time_stamp >= '2010-02-10'::timestamptz and time_stamp < '2010-02-11'::timestamptz 

Кроме того, убедитесь, что проверка состояния на столе определяется таким же образом ... EG: ПРОВЕРКА (time_stamp < «2010-02-10» :: timestamptz)

2

У меня была такая же проблема, и она сводилась к двум причинам в моем случае:

  1. я индексированного столбца типа timestamp WITH time zone и ограничение раздела этим столбцом с типом timestamp WITHOUT time zone.

  2. После устранения ограничений ANALYZE всех дочерних таблиц.

Edit: еще немного знаний - это важно помнить, что ограничение изоляции (что позволяет PG пропустить сканирование некоторых таблиц на основе ваших критериев разделения) не работает с, цитирую: non-immutable function such as CURRENT_TIMESTAMP

У меня были запросы с CURRENT_DATE, и это было частью моей проблемы.