powered by simpleCommunicator - 2.0.52     © 2025 Programmizd 02
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
14 сообщений из 14, страница 1 из 1
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40022911
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Коллеги, что-то вдруг уперлись в странную проблему (сервер postgresql 12)
Есть такой запрос:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
select
    12769, '82836421945482914', 1, _iv.id, _iv.respondent_id, _iv.user_id, _iv.user_client_id
from 
  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
  left outer join counter_interviews civ on (civ.counter_id = '82836421945482914' and civ.version_idx = 1 and civ.interview_id = _iv.id)
where
  r.project_id = 12769 and civ.id is null and
  (exists(select id from answers where (interview_id = _iv.id and question_number = 2) and (answer_code = 28 or answer_code = 29 or answer_code = 30)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 3) and (answer_code = 1)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 4) and (open_value_num >= 65 and open_value_num < 76)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 999)))



У него такой план:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
Nested Loop Semi Join  (cost=1207.29..95599.03 rows=1 width=72) (actual time=698.523..698.524 rows=0 loops=1)
  ->  Nested Loop Semi Join  (cost=1206.73..95598.36 rows=1 width=56) (actual time=698.523..698.523 rows=0 loops=1)
        ->  Nested Loop Semi Join  (cost=1206.16..95597.42 rows=1 width=48) (actual time=299.810..698.485 rows=6 loops=1)
              ->  Nested Loop Semi Join  (cost=1205.60..95596.72 rows=1 width=40) (actual time=253.203..698.406 rows=21 loops=1)
                    ->  Gather  (cost=1205.03..95595.89 rows=1 width=32) (actual time=0.844..117.631 rows=241883 loops=1)
                          Workers Planned: 4
                          Workers Launched: 4
                          ->  Hash Left Join  (cost=205.03..94595.79 rows=1 width=32) (actual time=0.438..239.976 rows=48377 loops=5)
                                Hash Cond: (_iv.id = civ.interview_id)
                                Filter: (civ.id IS NULL)
                                ->  Nested Loop  (cost=0.99..94238.79 rows=58270 width=32) (actual time=0.185..226.922 rows=48377 loops=5)
                                      ->  Parallel Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..18002.49 rows=46476 width=8) (actual time=0.108..34.951 rows=34056 loops=5)
                                            Index Cond: (project_id = 12769)
                                            Heap Fetches: 169550
                                      ->  Index Scan using ix_interviews_respondentid_id on interviews _iv  (cost=0.43..1.62 rows=2 width=32) (actual time=0.003..0.005 rows=1 loops=170278)
                                            Index Cond: (respondent_id = r.id)
                                ->  Hash  (cost=200.39..200.39 rows=292 width=16) (actual time=0.072..0.073 rows=0 loops=5)
                                      Buckets: 1024  Batches: 1  Memory Usage: 8kB
                                      ->  Index Scan using uix_counterinterviews_counterid_versionidx_interviewid on counter_interviews civ  (cost=0.56..200.39 rows=292 width=16) (actual time=0.072..0.072 rows=0 loops=5)
                                            Index Cond: ((counter_id = '82836421945482914'::bigint) AND (version_idx = 1))
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.69 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=241883)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
                          Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
                          Rows Removed by Filter: 0
                          Heap Fetches: 2713
              ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.63 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=21)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                    Heap Fetches: 6
        ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.75 rows=1 width=8) (actual time=0.005..0.005 rows=0 loops=6)
              Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
              Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
              Rows Removed by Filter: 1
  ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.65 rows=2 width=8) (never executed)
        Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
        Heap Fetches: 0
Planning Time: 7.312 ms
Execution Time: 732.031 ms

И в этом плане всё нас устраивает. К нему шли долго, включая обсуждения на sql.ru
Но, этот запрос исполняется на самом деле в такой вот обертке:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
insert into counter_interviews
  (project_id, counter_id, version_idx, interview_id, respondent_id, user_id, user_client_id)
select
    12769, '82836421945482914', 1, _iv.id, _iv.respondent_id, _iv.user_id, _iv.user_client_id
from 
  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
  left outer join counter_interviews civ on (civ.counter_id = '82836421945482914' and civ.version_idx = 1 and civ.interview_id = _iv.id)
where
  r.project_id = 12769 and civ.id is null and
  (exists(select id from answers where (interview_id = _iv.id and question_number = 2) and (answer_code = 28 or answer_code = 29 or answer_code = 30)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 3) and (answer_code = 1)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 4) and (open_value_num >= 65 and open_value_num < 76)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 999)))



И вот тут случается странное. Когда появляется insert into... то план меняется на такой:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
Insert on counter_interviews  (cost=206.73..266474.16 rows=1 width=68) (actual time=21474.522..21474.522 rows=0 loops=1)
  ->  Nested Loop Semi Join  (cost=206.73..266474.16 rows=1 width=68) (actual time=21474.520..21474.520 rows=0 loops=1)
        ->  Nested Loop Semi Join  (cost=206.17..266473.48 rows=1 width=56) (actual time=21474.520..21474.520 rows=0 loops=1)
              ->  Nested Loop Semi Join  (cost=205.60..266472.54 rows=1 width=48) (actual time=3845.372..21474.480 rows=6 loops=1)
                    ->  Nested Loop Semi Join  (cost=205.04..266471.84 rows=1 width=40) (actual time=3825.813..21474.381 rows=21 loops=1)
                          ->  Nested Loop  (cost=204.47..266471.01 rows=1 width=32) (actual time=202.621..20930.507 rows=241883 loops=1)
                                ->  Hash Left Join  (cost=204.04..266470.54 rows=1 width=32) (actual time=24.564..3854.011 rows=8259432 loops=1)
                                      Hash Cond: (_iv.id = civ.interview_id)
                                      Filter: (civ.id IS NULL)
                                      ->  Seq Scan on interviews _iv  (cost=0.00..245526.29 rows=7901029 width=32) (actual time=0.008..826.951 rows=8259432 loops=1)
                                      ->  Hash  (cost=200.39..200.39 rows=292 width=16) (actual time=0.015..0.016 rows=0 loops=1)
                                            Buckets: 1024  Batches: 1  Memory Usage: 8kB
                                            ->  Index Scan using uix_counterinterviews_counterid_versionidx_interviewid on counter_interviews civ  (cost=0.56..200.39 rows=292 width=16) (actual time=0.015..0.015 rows=0 loops=1)
                                                  Index Cond: ((counter_id = '82836421945482914'::bigint) AND (version_idx = 1))
                                ->  Index Scan using respondents_pkey on respondents r  (cost=0.43..0.47 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=8259432)
                                      Index Cond: (id = _iv.respondent_id)
                                      Filter: (project_id = 12769)
                                      Rows Removed by Filter: 1
                          ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.69 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=241883)
                                Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
                                Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
                                Rows Removed by Filter: 0
                                Heap Fetches: 2713
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.63 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=21)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                          Heap Fetches: 6
              ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.75 rows=1 width=8) (actual time=0.005..0.005 rows=0 loops=6)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
                    Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
                    Rows Removed by Filter: 1
        ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.65 rows=2 width=8) (never executed)
              Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
              Heap Fetches: 0
Planning Time: 5.438 ms
JIT:
  Functions: 37
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 6.632 ms, Inlining 0.000 ms, Optimization 1.239 ms, Emission 22.979 ms, Total 30.851 ms
Execution Time: 21481.367 ms

Т.е. появился почему-то Seq Scan on interviews и как итог 21 секунда на запрос, хотя сама выборка без insert 732 ms и она выдает 0 строк, т.е. и вставлять ничего не надо.

Что не так? Куда смотреть? Что крутить?
Беда пришла такая вдруг, она не на всех запросах проявляется, но тут - гарантировано.

Явно мешает join в таблицу, в которую будет и insert. Но почему?
Помогите разобраться.
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40022913
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Таблица counter_interviews имеет такую структуру:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
CREATE TABLE public.counter_interviews (
	id bigserial NOT NULL DEFAULT nextval('counter_interviews_id_seq'::regclass),
	created timestamp NOT NULL DEFAULT timezone('UTC'::text, now()),
	project_id int8 NOT NULL,
	counter_id int8 NOT NULL,
	interview_id int8 NOT NULL,
	version_idx int4 NOT NULL,
	respondent_id int8 NOT NULL,
	user_id int8 NOT NULL,
	user_client_id int8 NOT NULL,
	CONSTRAINT counter_interviews_pkey PRIMARY KEY (id),
	CONSTRAINT fk_counterinterviews_counterid FOREIGN KEY (counter_id) REFERENCES counters(id) ON UPDATE RESTRICT ON DELETE CASCADE
);
CREATE INDEX ix_counterinterviews_projectid ON public.counter_interviews USING btree (project_id);
CREATE UNIQUE INDEX uix_counterinterviews_counterid_versionidx_interviewid ON public.counter_interviews USING btree (counter_id, version_idx, interview_id);
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40022918
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Несколько улучшается (заметно, но без понимания всё равно) ситуация, если заменить civ.id is null на civ.interview_id is null, время выполнения получается 3000 ms примерно. Такое же время выходит если вообще убрать join в counter_interviews (делается это для проверки дубликатов), заменив его на on conflict do nothing. Но... в плане запроса всё равно есть seq scan и получаем 3000 ms при вставке 0 строк из запроса, который сам по себе выполняется за 700ms.

Запрос без join:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
insert into counter_interviews
  (project_id, counter_id, version_idx, interview_id, respondent_id, user_id, user_client_id)
select
    12769, '82836421945482914', 1, _iv.id, _iv.respondent_id, _iv.user_id, _iv.user_client_id
from 
  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
where
  r.project_id = 12769 and 
  (exists(select id from answers where (interview_id = _iv.id and question_number = 2) and (answer_code = 28 or answer_code = 29 or answer_code = 30)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 3) and (answer_code = 1)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 4) and (open_value_num >= 65 and open_value_num < 76)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 999)))
on conflict do nothing;



Его план:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
Insert on counter_interviews  (cost=21722.81..431784.69 rows=1 width=68) (actual time=2978.114..2978.114 rows=0 loops=1)
  Conflict Resolution: NOTHING
  Tuples Inserted: 0
  Conflicting Tuples: 0
  ->  Nested Loop Semi Join  (cost=21722.81..431784.69 rows=1 width=68) (actual time=2978.112..2978.112 rows=0 loops=1)
        ->  Nested Loop Semi Join  (cost=21722.24..431783.85 rows=1 width=56) (actual time=377.985..2977.856 rows=73 loops=1)
              ->  Nested Loop Semi Join  (cost=21721.68..431768.59 rows=20 width=48) (actual time=274.200..2974.595 rows=1055 loops=1)
                    ->  Nested Loop Semi Join  (cost=21721.11..429948.58 rows=2866 width=40) (actual time=272.470..2967.692 rows=2409 loops=1)
                           ->  Hash Join  (cost=21720.55..287987.05 rows=233080 width=32) (actual time=164.919..2445.680 rows=241883 loops=1)
                                Hash Cond: (_iv.respondent_id = r.id)
                                ->  Seq Scan on interviews _iv  (cost=0.00..245526.29 rows=7901029 width=32) (actual time=0.011..784.094 rows=8259441 loops=1)
                                ->  Hash  (cost=19396.76..19396.76 rows=185903 width=8) (actual time=145.899..145.900 rows=170278 loops=1)
                                      Buckets: 262144  Batches: 1  Memory Usage: 8700kB
                                      ->  Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..19396.76 rows=185903 width=8) (actual time=21.295..113.534 rows=170278 loops=1)
                                            Index Cond: (project_id = 12769)
                                            Heap Fetches: 169550
                           ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.65 rows=2 width=8) (actual time=0.002..0.002 rows=0 loops=241883)
                                Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
                                Heap Fetches: 1522
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.63 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=2409)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                          Heap Fetches: 637
              ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.75 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=1055)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
                    Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
                    Rows Removed by Filter: 1
        ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.69 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=73)
              Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
              Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
              Rows Removed by Filter: 1
              Heap Fetches: 41
Planning Time: 3.841 ms
JIT:
  Functions: 27
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 6.498 ms, Inlining 0.000 ms, Optimization 2.050 ms, Emission 18.823 ms, Total 27.370 ms
Execution Time: 2985.121 ms
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40022920
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Trizno,

Все просто в select плане есть слово -> Parallel в 4 worker
любые пишущие запросы не параллеляться (архитектурное ограничение) поэтому выполняется в 1 поток и в 4 раза дольше.
Есть подкрутить настойки базы можно в 8 потоков select делать и еще в 2 раза быстрее но insert от этого не ускорится.
Учитывая https://www.postgresql.org/docs/12/when-can-parallel-query-be-used.html
документацияEven when it is in general possible for parallel query plans to be generated, the planner will not generate them for a given query if any of the following are true:

The query writes any data or locks any database rows. If a query contains a data-modifying operation either at the top level or within a CTE, no parallel plans for that query will be generated. As an exception, the commands CREATE TABLE ... AS, SELECT INTO, and CREATE MATERIALIZED VIEW which create a new table and populate it can use a parallel plan.


Можно получить нужную вам скорость через

begin;
create temp table t1 on commit drop as ваш select;
insert into counter_interviews select * from t1;
commit;

но это хорошо работает пока не слишком часто вызывается (ну там не чаще 10 раз в секунду лучше меньше).


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40022965
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Спасибо. Пока не понятно только - почему в select-плане есть только index scan и index only scan, а в insert-select плане появляется seq scan на 8 млн строк? Ну и разница выходила (пока был left join + civ.id is null) 732 ms против 21481 ms, т.е. совсем не в 4 раза, а почти в 30.

Вариант с temp не подойдет, эти запросы могут идти пачками по несколько тыс. штук.
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023028
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Trizno,

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

теперь к плану и запросу.

покажите что у вас показывает
show random_page_cost;
show seq_page_cost;
show effective_cache_size;

и
set max_parallel_workers_per_gather to 0;
explain (analyze, costs, buffers, timing) ваш SELECT (не insert);

и второй вариант
set max_parallel_workers_per_gather to 0;
set enable_seqscan to 0;
explain (analyze, costs, buffers, timing) ваш SELECT (не insert);



--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023285
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Примерно так:

random_page_cost = 1.1 (база на ssd дисках)
seq_page_cost = 1
effective_cache_size = 45GB

Запрос после set max_parallel_workers_per_gather to 0

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
explain (analyze, costs, buffers, timing)
select
    12769, '82836421945482914', 1, _iv.id, _iv.respondent_id, _iv.user_id, _iv.user_client_id
from 
  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
where
  r.project_id = 12769 and 
  (exists(select id from answers where (interview_id = _iv.id and question_number = 2) and (answer_code = 28 or answer_code = 29 or answer_code = 30)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 3) and (answer_code = 1)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 4) and (open_value_num >= 65 and open_value_num < 76)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 999)))



Результат:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
Nested Loop Semi Join  (cost=22188.90..432435.12 rows=1 width=72) (actual time=9219.526..9219.526 rows=0 loops=1)
  Buffers: shared hit=1060559 read=128440 dirtied=1706
  I/O Timings: read=4722.202
  ->  Nested Loop Semi Join  (cost=22188.34..432434.23 rows=1 width=56) (actual time=756.314..9218.999 rows=74 loops=1)
        Buffers: shared hit=1060213 read=128440 dirtied=1706
        I/O Timings: read=4722.202
        ->  Nested Loop Semi Join  (cost=22187.77..432418.94 rows=20 width=48) (actual time=512.779..9150.586 rows=1062 loops=1)
              Buffers: shared hit=1055295 read=128048 dirtied=1706
              I/O Timings: read=4659.262
              ->  Nested Loop Semi Join  (cost=22187.21..430620.81 rows=2824 width=40) (actual time=509.107..9125.970 rows=2424 loops=1)
                    Buffers: shared hit=1045015 read=127929 dirtied=1706
                    I/O Timings: read=4644.675
                    ->  Hash Join  (cost=22186.64..288453.14 rows=233080 width=32) (actual time=280.805..6582.086 rows=244885 loops=1)
                          Hash Cond: (_iv.respondent_id = r.id)
                          Buffers: shared hit=80568 read=111191 dirtied=1692
                          I/O Timings: read=2753.737
                          ->  Seq Scan on interviews _iv  (cost=0.00..245526.29 rows=7901029 width=32) (actual time=0.399..4071.881 rows=8338445 loops=1)
                                Buffers: shared hit=57393 read=109123 dirtied=1668
                                I/O Timings: read=2717.509
                          ->  Hash  (cost=19835.35..19835.35 rows=188103 width=8) (actual time=234.719..234.719 rows=172764 loops=1)
                                Buckets: 262144  Batches: 1  Memory Usage: 8797kB
                                Buffers: shared hit=23172 read=2068 dirtied=24
                                I/O Timings: read=36.229
                                ->  Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..19835.35 rows=188103 width=8) (actual time=22.157..184.648 rows=172764 loops=1)
                                      Index Cond: (project_id = 12769)
                                      Heap Fetches: 175036
                                      Buffers: shared hit=23172 read=2068 dirtied=24
                                      I/O Timings: read=36.229
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.65 rows=2 width=8) (actual time=0.010..0.010 rows=0 loops=244885)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
                          Heap Fetches: 1537
                          Buffers: shared hit=964447 read=16738 dirtied=14
                          I/O Timings: read=1890.938
              ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.64 rows=1 width=8) (actual time=0.009..0.009 rows=0 loops=2424)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                    Heap Fetches: 644
                    Buffers: shared hit=10280 read=119
                    I/O Timings: read=14.587
        ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.76 rows=1 width=8) (actual time=0.064..0.064 rows=0 loops=1062)
              Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
              Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
              Rows Removed by Filter: 1
              Buffers: shared hit=4918 read=392
              I/O Timings: read=62.941
  ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.72 rows=1 width=8) (actual time=0.006..0.006 rows=0 loops=74)
        Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
        Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
        Rows Removed by Filter: 1
        Heap Fetches: 41
        Buffers: shared hit=346
Planning Time: 6.496 ms
JIT:
  Functions: 27
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 5.275 ms, Inlining 0.000 ms, Optimization 1.159 ms, Emission 20.488 ms, Total 26.922 ms
Execution Time: 9291.632 ms

И тот же запрос после дополнительного set enable_seqscan to 0

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
Nested Loop Semi Join  (cost=3.25..470668.32 rows=1 width=72) (actual time=1318.299..1318.299 rows=0 loops=1)
  Buffers: shared hit=1783271 read=2825
  I/O Timings: read=107.277
  ->  Nested Loop Semi Join  (cost=2.69..470667.44 rows=1 width=56) (actual time=21.100..1318.049 rows=74 loops=1)
        Buffers: shared hit=1782923 read=2825
        I/O Timings: read=107.277
        ->  Nested Loop Semi Join  (cost=2.12..470652.14 rows=20 width=48) (actual time=21.081..1314.664 rows=1062 loops=1)
              Buffers: shared hit=1777613 read=2825
              I/O Timings: read=107.277
              ->  Nested Loop Semi Join  (cost=1.55..468854.01 rows=2824 width=40) (actual time=21.072..1307.315 rows=2424 loops=1)
                    Buffers: shared hit=1767055 read=2825
                    I/O Timings: read=107.277
                    ->  Nested Loop  (cost=0.99..326686.12 rows=233080 width=32) (actual time=18.487..705.087 rows=244906 loops=1)
                          Buffers: shared hit=785502 read=2825
                          I/O Timings: read=107.277
                          ->  Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..19835.35 rows=188103 width=8) (actual time=0.022..78.466 rows=172774 loops=1)
                                Index Cond: (project_id = 12769)
                                Heap Fetches: 172067
                                Buffers: shared hit=25223
                          ->  Index Scan using ix_interviews_respondentid_id on interviews _iv  (cost=0.43..1.61 rows=2 width=32) (actual time=0.002..0.003 rows=1 loops=172774)
                                Index Cond: (respondent_id = r.id)
                                Buffers: shared hit=760279 read=2825
                                I/O Timings: read=107.277
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.65 rows=2 width=8) (actual time=0.002..0.002 rows=0 loops=244906)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
                          Heap Fetches: 1537
                          Buffers: shared hit=981553
              ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.64 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=2424)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                    Heap Fetches: 644
                    Buffers: shared hit=10558
        ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.76 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=1062)
              Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
              Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
              Rows Removed by Filter: 1
              Buffers: shared hit=5310
  ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.72 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=74)
        Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
        Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
        Rows Removed by Filter: 1
        Heap Fetches: 41
        Buffers: shared hit=348
Planning Time: 4.286 ms
JIT:
  Functions: 23
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 5.623 ms, Inlining 0.000 ms, Optimization 1.107 ms, Emission 16.936 ms, Total 23.665 ms
Execution Time: 1324.334 ms
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023415
Павел Лузанов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Trizno

Код: sql
1.
2.
3.
4.
5.
6.
7.
...
where
  r.project_id = 12769 and 
  (exists(select id from answers where (interview_id = _iv.id and question_number = 2) and (answer_code = 28 or answer_code = 29 or answer_code = 30)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 3) and (answer_code = 1)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 4) and (open_value_num >= 65 and open_value_num < 76)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 999)))


Поэкспериментируйте с расширенной статистикой для таблицы answers со столбцами interview_id, question_number, answer_code, open_value_num.
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023493
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Trizno,

Ага тогда давайте упрощать задачу далее...

Что показывает

Код: plsql
1.
2.
3.
4.
explain analyze SELECT _iv.* 
FROM  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
WHERE r.project_id = 12769;



и тот же explain analyze после установки set max_parallel_workers_per_gather to 0;

Если там будет разница и по плану и по скорости сильная мы дойдем до разумного минимального плана где легко можно попробовать понять что не так с планированием.
Мое мнение (ГИПОТЕЗА) что нормализации плана поможет или установка random_page_cost=0.11 seq_page_cost=0.1(т.е. уменьшить в 10 раз) или установка cpu_tuple_cost=0.1 (увеличить в 10 раз).


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023494
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Первый запрос вот так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
Gather  (cost=1000.99..119682.22 rows=233080 width=949) (actual time=12.123..750.075 rows=247105 loops=1)
  Workers Planned: 4
  Workers Launched: 4
  ->  Nested Loop  (cost=0.99..95374.22 rows=58270 width=949) (actual time=9.741..627.560 rows=49421 loops=5)
        ->  Parallel Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..18530.92 rows=47165 width=8) (actual time=0.497..156.346 rows=34854 loops=5)
              Index Cond: (project_id = 12769)
              Heap Fetches: 175399
        ->  Index Scan using ix_interviews_respondentid_id on interviews _iv  (cost=0.43..1.61 rows=2 width=949) (actual time=0.008..0.012 rows=1 loops=174268)
              Index Cond: (respondent_id = r.id)
Planning Time: 3.046 ms
JIT:
  Functions: 30
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 6.499 ms, Inlining 0.000 ms, Optimization 3.472 ms, Emission 40.225 ms, Total 50.196 ms
Execution Time: 833.536 ms

После set max_parallel_workers_per_gather to 0; так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
Hash Join  (cost=22304.10..288570.60 rows=233080 width=949) (actual time=182.495..5217.615 rows=247105 loops=1)
  Hash Cond: (_iv.respondent_id = r.id)
  ->  Seq Scan on interviews _iv  (cost=0.00..245526.29 rows=7901029 width=949) (actual time=0.465..3380.945 rows=8360402 loops=1)
  ->  Hash  (cost=19945.86..19945.86 rows=188659 width=8) (actual time=138.994..138.994 rows=174268 loops=1)
        Buckets: 262144  Batches: 1  Memory Usage: 8856kB
        ->  Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..19945.86 rows=188659 width=8) (actual time=11.009..109.461 rows=174268 loops=1)
              Index Cond: (project_id = 12769)
              Heap Fetches: 173540
Planning Time: 0.480 ms
JIT:
  Functions: 10
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 2.972 ms, Inlining 0.000 ms, Optimization 0.801 ms, Emission 10.011 ms, Total 13.784 ms
Execution Time: 5229.072 ms

Разница по скорости в 6 раз получилась.
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023497
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Trizno,

Угу вот и получили минимальный проблемный запрос собственно (и ни exists ни insert ни " расширенной статистикой для таблицы answers" тут не причем).

Оценки количества строк - в порядке
оценки селективности join - в порядке....
а план - кривой.

А какой план будет если сделать
set max_parallel_workers_per_gather to 0;
set seq_page_cost to 0.1;
set random_page_cost to 0.11;
и повторить explain analyze что делали.

у меня все таки теория что *_cost расставлены в базе не в соответствии с реальностью.


--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023532
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

После этих трех set-ов запрос:

Код: plsql
1.
2.
3.
4.
explain analyze SELECT _iv.* 
FROM  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
WHERE r.project_id = 12769;



Работает так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Nested Loop  (cost=0.99..118511.21 rows=233081 width=949) (actual time=12.754..565.323 rows=247252 loops=1)
  ->  Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..4968.68 rows=188719 width=8) (actual time=0.029..71.099 rows=174324 loops=1)
        Index Cond: (project_id = 12769)
        Heap Fetches: 173597
  ->  Index Scan using ix_interviews_respondentid_id on interviews _iv  (cost=0.43..0.58 rows=2 width=949) (actual time=0.002..0.002 rows=1 loops=174324)
        Index Cond: (respondent_id = r.id)
Planning Time: 0.506 ms
JIT:
  Functions: 6
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 2.174 ms, Inlining 0.000 ms, Optimization 1.154 ms, Emission 11.329 ms, Total 14.657 ms
Execution Time: 578.171 ms

А исходный запрос:

Код: plsql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
select
    12769, '82836421945482914', 1, _iv.id, _iv.respondent_id, _iv.user_id, _iv.user_client_id
from 
  interviews _iv
  inner join respondents r on (r.id = _iv.respondent_id)
where
  r.project_id = 12769 and 
  (exists(select id from answers where (interview_id = _iv.id and question_number = 2) and (answer_code = 28 or answer_code = 29 or answer_code = 30)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 3) and (answer_code = 1)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 4) and (open_value_num >= 65 and open_value_num < 76)) and
  exists(select id from answers where (interview_id = _iv.id and question_number = 999)))



Так (после 2-3 выполнений):

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
Nested Loop Semi Join  (cost=3.25..257194.26 rows=1 width=72) (actual time=1182.675..1182.675 rows=0 loops=1)
  ->  Nested Loop Semi Join  (cost=2.69..257193.47 rows=1 width=56) (actual time=21.737..1182.423 rows=74 loops=1)
        ->  Nested Loop Semi Join  (cost=2.12..257180.35 rows=20 width=48) (actual time=21.728..1179.231 rows=1064 loops=1)
              ->  Nested Loop Semi Join  (cost=1.55..255507.00 rows=2824 width=40) (actual time=21.719..1172.347 rows=2427 loops=1)
                    ->  Nested Loop  (cost=0.99..118512.82 rows=233080 width=32) (actual time=19.200..588.314 rows=247261 loops=1)
                          ->  Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..4968.78 rows=188722 width=8) (actual time=0.033..74.393 rows=174332 loops=1)
                                Index Cond: (project_id = 12769)
                                Heap Fetches: 173605
                          ->  Index Scan using ix_interviews_respondentid_id on interviews _iv  (cost=0.43..0.58 rows=2 width=32) (actual time=0.002..0.002 rows=1 loops=174332)
                                Index Cond: (respondent_id = r.id)
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.61 rows=2 width=8) (actual time=0.002..0.002 rows=0 loops=247261)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
                          Heap Fetches: 1540
              ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.59 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=2427)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                    Heap Fetches: 646
        ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.65 rows=1 width=8) (actual time=0.003..0.003 rows=0 loops=1064)
              Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
              Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
              Rows Removed by Filter: 1
  ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.68 rows=1 width=8) (actual time=0.002..0.002 rows=0 loops=74)
        Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
        Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
        Rows Removed by Filter: 1
        Heap Fetches: 41
Planning Time: 3.581 ms
JIT:
  Functions: 23
  Options: Inlining false, Optimization false, Expressions true, Deforming true
  Timing: Generation 5.589 ms, Inlining 0.000 ms, Optimization 1.904 ms, Emission 16.892 ms, Total 24.385 ms
Execution Time: 1188.451 ms

Он же при set max_parallel_workers_per_gather to 4; так:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
Nested Loop Semi Join  (cost=1003.25..67610.20 rows=1 width=72) (actual time=485.686..485.686 rows=0 loops=1)
  ->  Gather  (cost=1002.68..67609.40 rows=1 width=56) (actual time=4.927..539.742 rows=74 loops=1)
        Workers Planned: 4
        Workers Launched: 4
        ->  Nested Loop Semi Join  (cost=2.69..66609.30 rows=1 width=56) (actual time=35.387..423.167 rows=15 loops=5)
              ->  Nested Loop Semi Join  (cost=2.12..66605.96 rows=5 width=48) (actual time=3.074..421.945 rows=213 loops=5)
                    ->  Nested Loop Semi Join  (cost=1.55..66187.62 rows=706 width=40) (actual time=3.045..419.591 rows=485 loops=5)
                          ->  Nested Loop  (cost=0.99..31939.08 rows=58270 width=32) (actual time=0.223..199.237 rows=49453 loops=5)
                                ->  Parallel Index Only Scan using ix_respondents_projectid_id on respondents r  (cost=0.56..3553.37 rows=47180 width=8) (actual time=0.125..28.486 rows=34867 loops=5)
                                      Index Cond: (project_id = 12769)
                                      Heap Fetches: 173608
                                ->  Index Scan using ix_interviews_respondentid_id on interviews _iv  (cost=0.43..0.58 rows=2 width=32) (actual time=0.003..0.004 rows=1 loops=174334)
                                      Index Cond: (respondent_id = r.id)
                          ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_3  (cost=0.56..0.61 rows=2 width=8) (actual time=0.004..0.004 rows=0 loops=247263)
                                Index Cond: ((interview_id = _iv.id) AND (question_number = 999))
                                Heap Fetches: 1540
                    ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_1  (cost=0.56..0.59 rows=1 width=8) (actual time=0.004..0.004 rows=0 loops=2427)
                          Index Cond: ((interview_id = _iv.id) AND (question_number = 3) AND (answer_code = 1))
                          Heap Fetches: 646
              ->  Index Scan using ix_answers_interviewid_questionnumber_answercode on answers answers_2  (cost=0.56..0.65 rows=1 width=8) (actual time=0.005..0.005 rows=0 loops=1064)
                    Index Cond: ((interview_id = _iv.id) AND (question_number = 4))
                    Filter: ((open_value_num >= '65'::numeric) AND (open_value_num < '76'::numeric))
                    Rows Removed by Filter: 1
  ->  Index Only Scan using ix_answers_interviewid_questionnumber_answercode on answers  (cost=0.56..0.68 rows=1 width=8) (actual time=0.006..0.006 rows=0 loops=74)
        Index Cond: ((interview_id = _iv.id) AND (question_number = 2))
        Filter: ((answer_code = 28) OR (answer_code = 29) OR (answer_code = 30))
        Rows Removed by Filter: 1
        Heap Fetches: 41
Planning Time: 5.124 ms
Execution Time: 540.320 ms
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023537
Фотография Maxim Boguk
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alexey Trizno,

Ну вот теперь похоже на правду и то что я хотел добиться от базы.

Я бы новые seq_page_cost / random_page_cost внес в глобальный конфиг базы как более отражающие реальность в ваше случае.

Я уже давно заметил что 1:100 seq_page_cost / cpu_tuple_cost реальность не отражает для баз на ssd (и тем более для баз в основном в памяти) и 1:10 дает более разумные планы в среднем.

--
Maxim Boguk
лучшая поддержка PostgreSQL: dataegret.ru
...
Рейтинг: 0 / 0
Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
    #40023540
Alexey Trizno
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Maxim Boguk,

Спасибо! Попробуем, последим. Как раз для баз используем nvme-диски под основные данные (постоянного обращения) и ssd для хранения собираемых данных.
...
Рейтинг: 0 / 0
14 сообщений из 14, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / Почему появляется Seq Scan при insert into T from select, если в выборке есть join в T ?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]