PostgreSQL неправильно удаляет разделы, если я заменяю литерал цифры c в предложении where простым запросом, который возвращает 1 строку - PullRequest
1 голос
/ 20 апреля 2020

быстрый запрос

select ...
from table1 t1
join table2 t2 on t2.org_id = t1.org_id
where t1.org_id = 1

медленный запрос

select ...
from table1 t1
join table2 t2 on t2.org_id = t1.org_id
where t1.org_id = (select org_id from table3 where org_name = "abc" limit 1)

Единственная разница в двух запросах - это замена подстановки запрос для литерала. Я пробовал это на PostgreSQL 12.2 и 11.6 на AWS с RDS. table1 и table2 разделены на столбец org_id. table3 имеет первичный ключ org_id и уникальный индекс org_name. «предел 1» был добавлен в подзапрос медленного запроса, чтобы попытаться помочь оптимизатору.

быстрый запрос возвращается через 10 секунд для большинства организаций. медленный запрос занимает 30-100 секунд для большинства организаций.

Я пробовал разделы размером 128, 256, 384, 512, 1024, 2048 и 4096, из которых 384 - лучший.

План анализа быстрого запроса состоит из 15 строк и правильно использует только 1 раздел. План объяснения медленного запроса составляет 2 388 строк для 384 разделов и, по-видимому, использует только 1 раздел, но он учитывает все разделы.

1 Ответ

0 голосов
/ 20 апреля 2020

Вы можете попытаться создать стабильную функцию SQL для замены подзапроса. У меня есть следующий сценарий с PostgreSQL 12.2:

EXPLAIN ANALYZE 
select * 
from table1 t1
join table2 t2 on t2.org_id = t1.org_id
where t1.org_id = 1;
                                                   QUERY PLAN                                                   
----------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.00..67.87 rows=78 width=44) (actual time=0.017..0.017 rows=0 loops=1)
   ->  Seq Scan on table2 t2  (cost=0.00..41.88 rows=13 width=4) (actual time=0.011..0.012 rows=1 loops=1)
         Filter: (org_id = 1)
   ->  Materialize  (cost=0.00..25.03 rows=6 width=40) (actual time=0.003..0.003 rows=0 loops=1)
         ->  Seq Scan on part1 t1  (cost=0.00..25.00 rows=6 width=40) (actual time=0.001..0.002 rows=0 loops=1)
               Filter: (org_id = 1)
 Planning Time: 0.432 ms
 Execution Time: 0.046 ms
(8 rows)


EXPLAIN ANALYZE 
select * 
from table1 t1
join table2 t2 on t2.org_id = t1.org_id
where t1.org_id = (select org_id from table3 where org_name = 'abc' limit 1);
                                                   QUERY PLAN                                                   
----------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=4.31..176.25 rows=390 width=44) (actual time=0.023..0.023 rows=0 loops=1)
   InitPlan 1 (returns $0)
     ->  Limit  (cost=0.00..4.31 rows=1 width=4) (actual time=0.013..0.013 rows=1 loops=1)
           ->  Seq Scan on table3  (cost=0.00..25.88 rows=6 width=4) (actual time=0.010..0.010 rows=1 loops=1)
                 Filter: (org_name = 'abc'::text)
   ->  Append  (cost=0.00..125.15 rows=30 width=40) (actual time=0.022..0.023 rows=0 loops=1)
         ->  Seq Scan on part1 t1  (cost=0.00..25.00 rows=6 width=40) (actual time=0.002..0.002 rows=0 loops=1)
               Filter: (org_id = $0)
         ->  Seq Scan on part2 t1_1  (cost=0.00..25.00 rows=6 width=40) (never executed)
               Filter: (org_id = $0)
         ->  Seq Scan on part3 t1_2  (cost=0.00..25.00 rows=6 width=40) (never executed)
               Filter: (org_id = $0)
         ->  Seq Scan on part4 t1_3  (cost=0.00..25.00 rows=6 width=40) (never executed)
               Filter: (org_id = $0)
         ->  Seq Scan on part5 t1_4  (cost=0.00..25.00 rows=6 width=40) (never executed)
               Filter: (org_id = $0)
   ->  Materialize  (cost=0.00..41.94 rows=13 width=4) (never executed)
         ->  Seq Scan on table2 t2  (cost=0.00..41.88 rows=13 width=4) (never executed)
               Filter: (org_id = $0)
 Planning Time: 0.397 ms
 Execution Time: 0.129 ms
(21 rows)

create function f_get_org_id() returns int
language sql
stable
as
$$
select org_id from table3 where org_name = 'abc' limit 1
$$
;
CREATE FUNCTION

EXPLAIN ANALYZE 
select * 
from table1 t1
join table2 t2 on t2.org_id = t1.org_id
where t1.org_id = f_get_org_id()
                                                   QUERY PLAN                                                    
-----------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.00..2309.43 rows=390 width=44) (actual time=0.003..0.003 rows=0 loops=1)
   ->  Append  (cost=0.00..1625.15 rows=30 width=40) (actual time=0.003..0.003 rows=0 loops=1)
         Subplans Removed: 4
         ->  Seq Scan on part1 t1  (cost=0.00..325.00 rows=6 width=40) (actual time=0.002..0.002 rows=0 loops=1)
               Filter: (org_id = f_get_org_id())
   ->  Materialize  (cost=0.00..679.44 rows=13 width=4) (never executed)
         ->  Seq Scan on table2 t2  (cost=0.00..679.38 rows=13 width=4) (never executed)
               Filter: (org_id = f_get_org_id())
 Planning Time: 0.655 ms
 Execution Time: 0.091 ms
(10 rows)
...