Когда Postgresql сокращает разделы с помощью столбцов JOIN? - PullRequest
0 голосов
/ 29 сентября 2019

У меня есть две таблицы в базе данных Postgres 11:

client table
--------
client_id    integer
client_name  character_varying

file table
--------
file_id      integer
client_id    integer
file_name    character_varying

Таблица клиента не разделена, таблица файлов разделена по client_id (разделение по списку).Когда новый клиент вставляется в клиентскую таблицу, триггер создает новый раздел для файловой таблицы.Таблица файлов имеет ограничение внешнего ключа, ссылающееся на таблицу клиента по client_id.

Когда я выполняю этот SQL (где c.client_id = 1), все выглядит нормально:

explain  
select *
from client c
join file f using (client_id)
where c.client_id = 1;

Сокращение разделаиспользуется, сканируется только раздел file_p1:

Nested Loop  (cost=0.00..3685.05 rows=100001 width=82)
  ->  Seq Scan on client c  (cost=0.00..1.02 rows=1 width=29)
        Filter: (client_id = 1)
  ->  Append  (cost=0.00..2684.02 rows=100001 width=57)
        ->  Seq Scan on file_p1 f  (cost=0.00..2184.01 rows=100001 width=57)
              Filter: (client_id = 1)

Но когда я использую предложение where, например "where c.client_name = 'test'", база данных сканирует все разделы и не распознает, чтоclient_name "test" равно client_id 1:

explain  
select *
from client c
join file f using (client_id)
where c.client_name = 'test';

План выполнения:

Hash Join  (cost=1.04..6507.57 rows=100001 width=82)
  Hash Cond: (f.client_id = c.client_id)
  ->  Append  (cost=0.00..4869.02 rows=200002 width=57)
        ->  Seq Scan on file_p1 f  (cost=0.00..1934.01 rows=100001 width=57)
        ->  Seq Scan on file_p4 f_1  (cost=0.00..1934.00 rows=100000 width=57)
        ->  Seq Scan on file_pdefault f_2  (cost=0.00..1.00 rows=1 width=556)
  ->  Hash  (cost=1.02..1.02 rows=1 width=29)
        ->  Seq Scan on client c  (cost=0.00..1.02 rows=1 width=29)
              Filter: ((name)::text = 'test'::text)

Так что для этого SQL сканируются все разделы в таблице файлов.

Так должен ли каждый выбор использовать столбец, на который разбиты таблицы?Разве база данных не может отклоняться от критериев сокращения раздела?


Редактировать: Чтобы добавить некоторую информацию:

В прошлом я работал с Oracleбазы данных большую часть времени.

План выполнения будет выглядеть примерно так:

  1. Выполните полное сканирование таблицы на клиентской таблице с именем клиента, чтобы узнать client_id.
  2. Сделайте «PARTITION LIST» доступ к таблице файлов, где разработчик SQL заявляет PARTITION_START = KEY и PARTITION_STOP = KEY, чтобы указать, что точный раздел неизвестен при расчете плана выполнения, но доступ будет сделан только к спискуразделов, которые рассчитываются по client_id, найденному в таблице client.

Это то, что я ожидал и в Postgresql.

1 Ответ

1 голос
/ 29 сентября 2019

В документации указано, что возможно динамическое сокращение раздела

(...) Во время фактического выполнения плана запроса.Здесь также может быть выполнено удаление разделов для удаления разделов, используя значения, которые известны только во время фактического выполнения запроса.Это включает в себя значения из подзапросов и значения из параметров времени выполнения, например, из параметризованных объединений вложенных циклов.

Если я правильно понимаю, это относится к подготовленным операторам или запросам с подзапросами, которые предоставляют значение ключа раздела в качестве параметра.Используйте explain analyse, чтобы увидеть динамическое сокращение (мой пример данных содержит миллион строк в трех разделах):

explain analyze
select *
from file
where client_id = (
    select client_id
    from client
    where client_name = 'test');

Append  (cost=25.88..22931.88 rows=1000000 width=14) (actual time=0.091..96.139 rows=333333 loops=1)
  InitPlan 1 (returns $0)
    ->  Seq Scan on client  (cost=0.00..25.88 rows=6 width=4) (actual time=0.040..0.042 rows=1 loops=1)
          Filter: (client_name = 'test'::text)
          Rows Removed by Filter: 2
  ->  Seq Scan on file_p1  (cost=0.00..5968.66 rows=333333 width=14) (actual time=0.039..70.026 rows=333333 loops=1)
        Filter: (client_id = $0)
  ->  Seq Scan on file_p2  (cost=0.00..5968.68 rows=333334 width=14) (never executed)
        Filter: (client_id = $0)
  ->  Seq Scan on file_p3  (cost=0.00..5968.66 rows=333333 width=14) (never executed)
        Filter: (client_id = $0)
Planning Time: 0.423 ms
Execution Time: 109.189 ms

Обратите внимание, что сканирование для разделов p2 и p3 было never executed.

Ответваш точный вопрос, в Postgres не реализовано сокращение разделов в запросах с объединениями, описанными в этом вопросе (пока?)

...