У меня есть две таблицы в базе данных 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.
План выполнения там был бы что-то вроде
- Выполните полное сканирование таблицы клиента с именем клиента, чтобы узнать client_id.
- Выполните доступ «СПИСОК РАЗДЕЛОВ» к таблице файлов, где разработчик SQL указывает PARTITION_START = KEY и PARTITION_STOP = KEY, чтобы указать, что точный раздел не известен при расчете плана выполнения, но доступ будет осуществляться только к списку разделов, которые рассчитываются на основе client_id, найденного в таблице client.
Это то, чего я ожидал и от Postgresql.
client_name = 'test'
означаетclient_id = 1
, до выполнения запроса. - person klin   schedule 29.09.2019