Эффективный запрос к многораздельной таблице Postgres - PullRequest
11 голосов
/ 10 февраля 2010

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

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 для каждого раздела, который в настоящее время определен?

РЕДАКТИРОВАТЬ: У меня включено ограничение_обязания (спасибо @Vinko Vrsalovic)

Ответы [ 3 ]

5 голосов
/ 10 февраля 2010

Вы пробовали исключение ограничений (раздел 5.9.4 в документе, на который вы ссылались)

Исключение ограничения - это запрос методика оптимизации, которая улучшает производительность для секционированных таблиц определяется описанным способом выше. Как пример:

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

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

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

4 голосов
/ 06 июля 2010

У меня была похожая проблема, которую я смог исправить, приведя условия в WHERE. EG: (при условии, что столбец time_stamp имеет тип timestamptz)

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

Кроме того, убедитесь, что условие CHECK для таблицы определено таким же образом ... НАПРИМЕР: ПРОВЕРКА (отметка времени <'2010-02-10' :: отметка времени) </p>

3 голосов
/ 01 апреля 2013

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

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

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

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

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

...