Настройка небольшой тестовой БД, добавление нескольких строк и выполнение запроса:
CREATE TABLE client
(
client_id integer PRIMARY KEY,
client_name text
);
CREATE TABLE client_additional
(
client_id integer PRIMARY KEY,
client_age integer
);
INSERT INTO client (client_id, client_name) VALUES (generate_series(1,100000),'Phil');
INSERT INTO client_additional (client_id, client_age) VALUES (generate_series(1,70000),21);
ANALYZE;
EXPLAIN ANALYZE SELECT
client_additional.client_id,
client_additional.client_age,
client.client_name
FROM
client
INNER JOIN
client_additional
ON
client.client_id = client_additional.client_id;
дал мне этот план:
Hash Join (cost=1885.00..3590.51 rows=70000 width=11) (actual time=158.958..44 1.222 rows=70000 loops=1)
Hash Cond: (client.client_id = client_additional.client_id)
-> Seq Scan on client (cost=0.00..1443.00 rows=100000 width=7) (actual time =0.019..100.318 rows=100000 loops=1)
-> Hash (cost=1010.00..1010.00 rows=70000 width=8) (actual time=158.785..15 8.786 rows=70000 loops=1)
Buckets: 131072 Batches: 1 Memory Usage: 3759kB
-> Seq Scan on client_additional (cost=0.00..1010.00 rows=70000 width =8) (actual time=0.016..76.507 rows=70000 loops=1)
Planning Time: 0.357 ms
Execution Time: 506.739 ms
То, что вы можете видеть из этой таблицы, - обе таблицыбыли последовательно отсканированы, значения из каждой таблицы были хэшированы, и было выполнено хеш-соединение. Постгрес определил, что это оптимальный способ выполнить этот запрос.
Если вы воссоздаете таблицы без первичного ключа (и, следовательно, удаляете неявный индекс для каждого столбца PK), вы получаете точно такой же планТак как Postgres определил, что самый быстрый способ выполнить этот запрос - игнорировать индексы и хэшировать значения таблицы, а затем выполнить хеш-соединение с двумя наборами хэшированных значений, чтобы получить результат.
После измененияколичество строк в клиентской таблице примерно так:
TRUNCATE Client;
INSERT INTO client (client_id, client_name) VALUES (generate_series(1,200000),'phil');
ANALYZE;
Затем я повторно запустил тот же запрос и вместо этого вижу этот план:
Merge Join (cost=1.04..5388.45 rows=70000 width=13) (actual time=0.050..415.50
3 rows=70000 loops=1)
Merge Cond: (client.client_id = client_additional.client_id)
-> Index Scan using client_pkey on client (cost=0.42..6289.42 rows=200000 width=9) (actual time=0.022..86.897 rows=70001 loops=1)
-> Index Scan using client_additional_pkey on client_additional (cost=0.29..2139.29 rows=70000 width=8) (actual time=0.016..86.818 rows=70000 loops=1)
Planning Time: 0.517 ms
Execution Time: 484.264 ms
Здесь вы можете видеть, что сканирование индексаЭто было сделано, так как Postgres определил, что этот план лучше, исходя из текущего числа строк в таблицах.
Дело в том, что Postgres будет использовать индексы, когда почувствует, что даст более быстрый результат,но пороги до их использования несколько выше, чем вы могли ожидать.
Всего наилучшего,
Phil