Postgres обрезка разделов - PullRequest
       27

Postgres обрезка разделов

2 голосов
/ 03 апреля 2012

У меня большой стол в Postgres.

Имя таблицы bigtable и столбцы:

integer    |timestamp   |xxx |xxx |...|xxx
category_id|capture_time|col1|col2|...|colN

Я разделил таблицу по модулю 10 из category_id и части даты столбца capture_time.

Таблицы разделов выглядят следующим образом:

CREATE TABLE myschema.bigtable_d000h0(
    CHECK ( category_id%10=0 AND capture_time >= DATE '2012-01-01' AND capture_time < DATE '2012-01-02')
) INHERITS (myschema.bigtable);

CREATE TABLE myschema.bigtable_d000h1(
    CHECK ( category_id%10=1 AND capture_time >= DATE '2012-01-01' AND capture_time < DATE '2012-01-02')
) INHERITS (myschema.bigtable);

Когда я выполняю запрос с category_id и capture_time в предложении where, разделы не удаляются должным образом.

explain select * from bigtable where capture_time >= '2012-01-01' and  capture_time < '2012-01-02' and category_id=100;

"Result  (cost=0.00..9476.87 rows=1933 width=216)"
"  ->  Append  (cost=0.00..9476.87 rows=1933 width=216)"
"        ->  Seq Scan on bigtable  (cost=0.00..0.00 rows=1 width=210)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h0 bigtable  (cost=0.00..1921.63 rows=1923 width=216)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h1 bigtable  (cost=0.00..776.93 rows=1 width=218)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h2 bigtable  (cost=0.00..974.47 rows=1 width=216)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h3 bigtable  (cost=0.00..1351.92 rows=1 width=214)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h4 bigtable  (cost=0.00..577.04 rows=1 width=217)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h5 bigtable  (cost=0.00..360.67 rows=1 width=219)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h6 bigtable  (cost=0.00..1778.18 rows=1 width=214)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h7 bigtable  (cost=0.00..315.82 rows=1 width=216)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h8 bigtable  (cost=0.00..372.06 rows=1 width=219)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"
"        ->  Seq Scan on bigtable_d000h9 bigtable  (cost=0.00..1048.16 rows=1 width=215)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100))"

Однако, если я добавлю точные критерии по модулю (category_id%10=0) в предложении where, это прекрасно работает

explain select * from bigtable where capture_time >= '2012-01-01' and  capture_time < '2012-01-02' and category_id=100 and category_id%10=0;

"Result  (cost=0.00..2154.09 rows=11 width=215)"
"  ->  Append  (cost=0.00..2154.09 rows=11 width=215)"
"        ->  Seq Scan on bigtable  (cost=0.00..0.00 rows=1 width=210)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100) AND ((category_id % 10) = 0))"
"        ->  Seq Scan on bigtable_d000h0 bigtable  (cost=0.00..2154.09 rows=10 width=216)"
"              Filter: ((capture_time >= '2012-01-01 00:00:00'::timestamp without time zone) AND (capture_time < '2012-01-02 00:00:00'::timestamp without time zone) AND (category_id = 100) AND ((category_id % 10) = 0))"

Можно ли как-нибудь правильно выполнить обрезку разделов без добавления модуля?условие в каждом запросе?

Ответы [ 2 ]

4 голосов
/ 03 апреля 2012

Дело в том, что для ограничения исключения PostgreSQL создаст неявный индекс . В вашем случае этот индекс будет частичным, потому что вы используете выражение для столбца, а не только его значение. И это указано в документации (см. Пример 11-2):

PostgreSQL не имеет сложного средства проверки теорем, способного распознавать математически эквивалентные выражения, написанные в разных формах. (Мало того, что такую ​​общую теорему чрезвычайно трудно создать, она, вероятно, будет слишком медленной, чтобы иметь какое-либо реальное применение.) Система может распознавать простые следствия из неравенства, например, «x <1» подразумевает «x <2»; <em>в противном случае условие предиката должно точно соответствовать части условия WHERE запроса, иначе индекс не будет признан пригодным для использования . Сопоставление происходит во время планирования запроса, а не во время выполнения.

Таким образом, ваши результаты - вы должны иметь точно такое же выражение, которое вы использовали при создании ограничения CHECK.

Для разбиения на основе HASH я предпочитаю 2 подхода:

  • добавить поле, которое может принимать ограниченный набор значений (10 в вашем случае), лучше всего, если оно существует по проекту;
  • задает диапазоны хеша так же, как вы задаете диапазоны меток времени: MINVALUE <= category_id <MAXVALUE </li>

Также возможно создание двухуровневого разбиения:

  • на первом уровне вы создаете 10 разделов на основе category_id HASH;
  • на втором уровне вы создаете необходимое количество разделов на основе ваших диапазонов дат.

Хотя я всегда стараюсь использовать только 1 столбец для разбиения, им легче управлять.

1 голос
/ 08 апреля 2012

Для тех, у кого такая же проблема: я пришел к выводу, что самый простой выход - изменить запросы, включив условие по модулю category_id%10=0

...