powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / загнать запрос по другой план
8 сообщений из 8, страница 1 из 1
загнать запрос по другой план
    #35283971
Gold_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доброго дня.
Подскажите как лучше изменить запрос
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
 EXPLAIN ANALYZE
                SELECT  dmain.kod_dok
                , dmain.naimp_dok
                , dmain.kod_kls_viddok 
                    FROM    dok.tdok_reg dreg 
			JOIN ONLY dok.tdok_main dmain ON   dmain.kod_dok =dreg.kod_dok     
                        
                    WHERE  
(
	 dmain.naimp_dok  ~* 'ОБЙНЕО'
)
                    AND  
dreg.data_reg_dok >='21.04.2007' 

                    AND  dreg.pr_dok_reg IN (  1  , 3  , 5  , 7 , 18  )  
                    GROUP  BY dmain.kod_dok, dmain.naimp_dok, dmain.kod_kls_viddok

            ORDER  BY naimp_dok

Получается такой план:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Sort  (cost= 2578 . 68 .. 2578 . 69  rows= 3  width= 47 ) (actual time= 1359 . 778 .. 1362 . 433  rows= 4087  loops= 1 )
  Sort Key: dmain.naimp_dok
  ->  HashAggregate  (cost= 2578 . 66 .. 2578 . 66  rows= 3  width= 47 ) (actual time= 1226 . 605 .. 1230 . 977  rows= 4087  loops= 1 )
        ->  Nested Loop  (cost= 0 . 00 .. 2578 . 64  rows= 3  width= 47 ) (actual time= 0 . 081 .. 1192 . 655  rows= 9669  loops= 1 )
              ->  Seq Scan on tdok_main dmain  (cost= 0 . 00 .. 2433 . 28  rows= 17  width= 47 ) (actual time= 0 . 031 .. 215 . 987  rows= 49240  loops= 1 )
                    Filter: ((naimp_dok)::text ~* 'ОБЙНЕО'::text)
              ->  Index Scan using i_tdok_reg_kod_dok on tdok_reg dreg  (cost= 0 . 00 .. 8 . 54  rows= 1  width= 4 ) (actual time= 0 . 018 .. 0 . 018  rows= 0  loops= 49240 )
                    Index Cond: ("outer".kod_dok = dreg.kod_dok)
                    Filter: ((data_reg_dok >= '2007-04-21'::date) AND ((pr_dok_reg =  1 ) OR (pr_dok_reg =  3 ) OR (pr_dok_reg =  5 ) OR (pr_dok_reg =  7 ) OR (pr_dok_reg =  18 )))
Total runtime:  1365 . 075  ms


Видно, что оптимизатор ошибся при оценке записей (не принципиально, я думаю, можно выбрать и менее селективную строчку - план останется таким же).

После
Код: plaintext
1.
SET enable_seqscan TO 'off';

План такой
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
Sort  (cost= 4491 . 60 .. 4491 . 61  rows= 3  width= 47 ) (actual time= 780 . 701 .. 783 . 385  rows= 4087  loops= 1 )
  Sort Key: dmain.naimp_dok
  ->  HashAggregate  (cost= 4491 . 57 .. 4491 . 57  rows= 3  width= 47 ) (actual time= 647 . 658 .. 651 . 969  rows= 4087  loops= 1 )
        ->  Nested Loop  (cost= 0 . 00 .. 4491 . 55  rows= 3  width= 47 ) (actual time= 156 . 330 .. 617 . 398  rows= 9669  loops= 1 )
              ->  Index Scan using tdok_main_pkey on tdok_main dmain  (cost= 0 . 00 .. 4346 . 19  rows= 17  width= 47 ) (actual time= 0 . 543 .. 240 . 163  rows= 49240  loops= 1 )
                    Filter: ((naimp_dok)::text ~* 'ОБЙНЕО'::text)
              ->  Index Scan using i_tdok_reg_kod_dok on tdok_reg dreg  (cost= 0 . 00 .. 8 . 54  rows= 1  width= 4 ) (actual time= 0 . 006 .. 0 . 006  rows= 0  loops= 49240 )
                    Index Cond: ("outer".kod_dok = dreg.kod_dok)
                    Filter: ((data_reg_dok >= '2007-04-21'::date) AND ((pr_dok_reg =  1 ) OR (pr_dok_reg =  3 ) OR (pr_dok_reg =  5 ) OR (pr_dok_reg =  7 ) OR (pr_dok_reg =  18 )))
Total runtime:  785 . 115  ms


Видно, что с tdok_main отработал чуть дольше, но Nested Loop быстрее. Как можно загнать под второй план?

всего строк в tdok_main 51000.
в настоящее время random_page_cost = 2.0
при уменьшении до 0.93 будет выбираться втрой план, Но это тоже не выход же..
Линтер ВС (postgresql 7.4.1)

спасибо
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35284129
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gold_Sort (actual rows=4087)для чего запрос возвращает несколько тысяч строк? после этого человек читает их? может быть сделать постраничную выдачу?

Gold_-> Seq Scan on tdok_main dmain (rows=17) (actual rows=49240)

Видно, что оптимизатор ошибся при оценке записейпричем сильно ошибся, на три порядка. из-за этого постгрес может выбирать далеко не оптимальный план. может быть попробовать понять причину такой неправильной оценки.

Gold_Видно, что с tdok_main отработал чуть дольше, но Nested Loop быстрее.не понятно, почему так произошло. два плана отличаются только secscan-ом по tdok_main против безусловного (отсутствует Index Cond) indexscan-а с одинаковыми фильтрами. безусловный indexscan должен быть медленнее (что наблюдается), и как следствие весь запрос должен быть медленнее (а тут наоборот). вы оба explain analyze делали на втором запросе, чтобы данные закэшировались с диска?

Gold_Как можно загнать под второй план?кажется, что второй план должен быть заведомо медленнее первого, поэтому тюнить под него не нужно.

Gold_Подскажите как лучше изменить запроссколько строк из таблицы tdok_reg удовлетворяют условию ((data_reg_dok >= '2007-04-21'::date) AND ((pr_dok_reg = 1) OR (pr_dok_reg = 3) OR (pr_dok_reg = 5) OR (pr_dok_reg = 7) OR (pr_dok_reg = 18)))?
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35284929
Gold_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBat Gold_Sort (actual rows=4087)для чего запрос возвращает несколько тысяч строк? после этого человек читает их? может быть сделать постраничную выдачу?

это часть запроса, далее будет агрегация, сортировка попала случайно.
LeXa NalBat
Gold_-> Seq Scan on tdok_main dmain (rows=17) (actual rows=49240)

Видно, что оптимизатор ошибся при оценке записейпричем сильно ошибся, на три порядка. из-за этого постгрес может выбирать далеко не оптимальный план. может быть попробовать понять причину такой неправильной оценки.

А как он принципе мог оценить?? Количество записей оцененное в таком запросе зависит от длины строчки (в моей версии так, кажись)
LeXa NalBat
Gold_Видно, что с tdok_main отработал чуть дольше, но Nested Loop быстрее.не понятно, почему так произошло. два плана отличаются только secscan-ом по tdok_main против безусловного (отсутствует Index Cond) indexscan-а с одинаковыми фильтрами. безусловный indexscan должен быть медленнее (что наблюдается), и как следствие весь запрос должен быть медленнее (а тут наоборот).

вот это и удивило.. решил, что в дальнейшем для Nested Loop более "удобные данные", теперь в этом сомневаюсь.
LeXa NalBat
вы оба explain analyze делали на втором запросе, чтобы данные закэшировались с диска?

Да
LeXa NalBat
Gold_Как можно загнать под второй план?кажется, что второй план должен быть заведомо медленнее первого, поэтому тюнить под него не нужно.

Наверное, не нужно. Только почему он быстрее отрабатывает. пробовал не один раз, хотя на меньшем количестве записей план с Seq Scan чуть быстрее отрабатывает
LeXa NalBat
Gold_Подскажите как лучше изменить запроссколько строк из таблицы tdok_reg удовлетворяют условию ((data_reg_dok >= '2007-04-21'::date) AND ((pr_dok_reg = 1) OR (pr_dok_reg = 3) OR (pr_dok_reg = 5) OR (pr_dok_reg = 7) OR (pr_dok_reg = 18)))?

10522
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35285003
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gold_ LeXa NalBatсколько строк из таблицы tdok_reg удовлетворяют условию ((data_reg_dok >= '2007-04-21'::date) AND ((pr_dok_reg = 1) OR (pr_dok_reg = 3) OR (pr_dok_reg = 5) OR (pr_dok_reg = 7) OR (pr_dok_reg = 18)))?10522при наличии индексов по tdok_reg (data_reg_dok) и tdok_main (kod_dok) попытаться добиться плана

Код: plaintext
1.
2.
3.
4.
5.
6.
-> Nested Loop
   -> Index Scan tdok_reg (data_reg_dok)
      Index Cond: data_reg_dok>='2007-04-21'
      Filter: pr_dok_reg= 1  OR pr_dok_reg= 3  OR ...
   -> Index Scan tdok_main (kod_dok)
      Index Cond: kod_dok="outer".kod_dok
      Filter: naimp_dok~*'ОБЙНЕО'

или переформулировать запрос

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
select ... from
 ( select * from dok.tdok_reg dreg where dreg.pr_dok_reg= 1  and dreg.data_reg_dok>='21.04.2007'
   union all
   select * from dok.tdok_reg dreg where dreg.pr_dok_reg= 3  and dreg.data_reg_dok>='21.04.2007'
   union all
   ...
 ) as dreg
join only dok.tdok_main dmain on dmain.kod_dok = dreg.kod_dok
where dmain.naimp_dok ~* 'ОБЙНЕО'
group by dmain.kod_dok, dmain.naimp_dok, dmain.kod_kls_viddok
order by naimp_dok

и при наличии индексов по tdok_reg (pr_dok_reg,data_reg_dok) и tdok_main (kod_dok) попытаться добиться плана

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
-> Nested Loop
   -> UnionAll
      -> Index Scan tdok_reg (pr_dok_reg,data_reg_dok)
         Index Cond: pr_dok_reg= 1  AND data_reg_dok>='2007-04-21'
      -> Index Scan tdok_reg (pr_dok_reg,data_reg_dok)
         Index Cond: pr_dok_reg= 3  AND data_reg_dok>='2007-04-21'
      ...
   -> Index Scan tdok_main (kod_dok)
      Index Cond: kod_dok="outer".kod_dok
      Filter: naimp_dok~*'ОБЙНЕО'
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35289041
Gold_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBat..

Код: plaintext
1.
2.
3.
4.
5.
6.
-> Nested Loop
   -> Index Scan tdok_reg (data_reg_dok)
      Index Cond: data_reg_dok>='2007-04-21'
      Filter: pr_dok_reg= 1  OR pr_dok_reg= 3  OR ...
   -> Index Scan tdok_main (kod_dok)
      Index Cond: kod_dok="outer".kod_dok
      Filter: naimp_dok~*'ОБЙНЕО'


Под такой сразу пытался... не получилось... как можно извернутся? (получалось только при использовании подзапросов)
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35289227
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: plaintext
1.
2.
3.
4.
5.
6.
-> Nested Loop
   -> Index Scan tdok_reg (data_reg_dok)
      Index Cond: data_reg_dok>='2007-04-21'
      Filter: pr_dok_reg= 1  OR pr_dok_reg= 3  OR ...
   -> Index Scan tdok_main (kod_dok)
      Index Cond: kod_dok="outer".kod_dok
      Filter: naimp_dok~*'ОБЙНЕО'

Gold_Под такой сразу пытался... не получилось...сколько строк в tdok_reg удовлетворяет условию data_reg_dok>='2007-04-21'?

установите enable_seqscan в 'off', удалите индекс tdok_main_pkey, и покажите explain analyze.

Gold_(получалось только при использовании подзапросов)покажите плиз запрос и explain analyze
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35294470
Gold_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
LeXa NalBat
Код: plaintext
1.
2.
3.
4.
5.
6.
-> Nested Loop
   -> Index Scan tdok_reg (data_reg_dok)
      Index Cond: data_reg_dok>='2007-04-21'
      Filter: pr_dok_reg= 1  OR pr_dok_reg= 3  OR ...
   -> Index Scan tdok_main (kod_dok)
      Index Cond: kod_dok="outer".kod_dok
      Filter: naimp_dok~*'ОБЙНЕО'

Gold_Под такой сразу пытался... не получилось...сколько строк в tdok_reg удовлетворяет условию data_reg_dok>='2007-04-21'?

10476
LeXa NalBat
установите enable_seqscan в 'off', удалите индекс tdok_main_pkey, и покажите explain analyze.

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Sort  (cost= 100002575 . 90 .. 100002575 . 91  rows= 3  width= 47 ) (actual time= 1312 . 162 .. 1313 . 478  rows= 4091  loops= 1 )
  Sort Key: dmain.naimp_dok
  ->  HashAggregate  (cost= 100002575 . 88 .. 100002575 . 88  rows= 3  width= 47 ) (actual time= 1243 . 004 .. 1246 . 614  rows= 4091  loops= 1 )
        ->  Nested Loop  (cost= 100000000 . 00 .. 100002575 . 86  rows= 3  width= 47 ) (actual time= 0 . 086 .. 1208 . 742  rows= 9677  loops= 1 )
              ->  Seq Scan on tdok_main dmain  (cost= 100000000 . 00 .. 100002430 . 47  rows= 17  width= 47 ) (actual time= 0 . 030 .. 219 . 869  rows= 49237  loops= 1 )
                    Filter: ((naimp_dok)::text ~* 'ОБЙНЕО'::text)
              ->  Index Scan using i_tdok_reg_kod_dok on tdok_reg dreg  (cost= 0 . 00 .. 8 . 54  rows= 1  width= 4 ) (actual time= 0 . 018 .. 0 . 019  rows= 0  loops= 49237 )
                    Index Cond: ("outer".kod_dok = dreg.kod_dok)
                    Filter: ((data_reg_dok >= '2007-04-21'::date) AND ((pr_dok_reg =  1 ) OR (pr_dok_reg =  3 ) OR (pr_dok_reg =  5 ) OR (pr_dok_reg =  7 ) OR (pr_dok_reg =  18 )))
Total runtime:  1315 . 379  ms


LeXa NalBat
Gold_(получалось только при использовании подзапросов)покажите плиз запрос и explain analyze
[/quot]

кажись обманул..
делал следующее
Код: 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.
EXPLAIN ANALYZE
                SELECT  dmain.kod_dok
                , dmain.naimp_dok
                , dmain.kod_kls_viddok 
                    FROM  ONLY dok.tdok_main dmain  
            WHERE  
 dmain.kod_dok IN  (
			SELECT  dreg.kod_dok FROM dok.tdok_reg dreg 
				WHERE  dreg.data_reg_dok >='21.04.2007' AND  dreg.pr_dok_reg IN (  1  , 3  , 5  , 7 , 18  ) 
GROUP BY   dreg.kod_dok
		 )
AND
 dmain.naimp_dok  ~* 'ОБЙНЕО'
     ORDER  BY naimp_dok;


Sort  (cost= 6809 . 37 .. 6809 . 38  rows= 1  width= 47 ) (actual time= 181 . 916 .. 183 . 675  rows= 4087  loops= 1 )
  Sort Key: dmain.naimp_dok
  ->  Nested Loop  (cost= 6004 . 20 .. 6809 . 36  rows= 1  width= 47 ) (actual time= 45 . 811 .. 106 . 867  rows= 4087  loops= 1 )
        ->  HashAggregate  (cost= 6004 . 20 .. 6004 . 20  rows= 200  width= 4 ) (actual time= 45 . 567 .. 49 . 339  rows= 4542  loops= 1 )
              ->  Subquery Scan "IN_subquery"  (cost= 5975 . 32 .. 5998 . 42  rows= 2310  width= 4 ) (actual time= 32 . 705 .. 41 . 727  rows= 4542  loops= 1 )
                    ->  HashAggregate  (cost= 5975 . 32 .. 5975 . 32  rows= 2310  width= 4 ) (actual time= 32 . 702 .. 36 . 660  rows= 4542  loops= 1 )
                          ->  Index Scan using i_tdok_reg_data_reg_dok on tdok_reg dreg  (cost= 0 . 00 .. 5956 . 55  rows= 7508  width= 4 ) (actual time= 0 . 088 .. 23 . 388  rows= 10394  loops= 1 )
                                Index Cond: (data_reg_dok >= '2007-04-21'::date)
                                Filter: ((pr_dok_reg =  1 ) OR (pr_dok_reg =  3 ) OR (pr_dok_reg =  5 ) OR (pr_dok_reg =  7 ) OR (pr_dok_reg =  18 ))
        ->  Index Scan using tdok_main_pkey on tdok_main dmain  (cost= 0 . 00 .. 4 . 01  rows= 1  width= 47 ) (actual time= 0 . 009 .. 0 . 009  rows= 1  loops= 4542 )
              Index Cond: (dmain.kod_dok = "outer".kod_dok)
              Filter: ((naimp_dok)::text ~* 'ОБЙНЕО'::text)
Total runtime:  186 . 087  ms

при формировании такого запроса решил, что будут сложности при других параметрах
...
Рейтинг: 0 / 0
загнать запрос по другой план
    #35294864
LeXa NalBat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Gold_делал следующее
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Sort  (cost= 6809 . 37 .. 6809 . 38  rows= 1  width= 47 ) (actual time= 181 . 916 .. 183 . 675  rows= 4087  loops= 1 )
  Sort Key: dmain.naimp_dok
  ->  Nested Loop  (cost= 6004 . 20 .. 6809 . 36  rows= 1  width= 47 ) (actual time= 45 . 811 .. 106 . 867  rows= 4087  loops= 1 )
        ->  HashAggregate  (cost= 6004 . 20 .. 6004 . 20  rows= 200  width= 4 ) (actual time= 45 . 567 .. 49 . 339  rows= 4542  loops= 1 )
              ->  Subquery Scan "IN_subquery"  (cost= 5975 . 32 .. 5998 . 42  rows= 2310  width= 4 ) (actual time= 32 . 705 .. 41 . 727  rows= 4542  loops= 1 )
                    ->  HashAggregate  (cost= 5975 . 32 .. 5975 . 32  rows= 2310  width= 4 ) (actual time= 32 . 702 .. 36 . 660  rows= 4542  loops= 1 )
                          ->  Index Scan using i_tdok_reg_data_reg_dok on tdok_reg dreg  (cost= 0 . 00 .. 5956 . 55  rows= 7508  width= 4 ) (actual time= 0 . 088 .. 23 . 388  rows= 10394  loops= 1 )
                                Index Cond: (data_reg_dok >= '2007-04-21'::date)
                                Filter: ((pr_dok_reg =  1 ) OR (pr_dok_reg =  3 ) OR (pr_dok_reg =  5 ) OR (pr_dok_reg =  7 ) OR (pr_dok_reg =  18 ))
        ->  Index Scan using tdok_main_pkey on tdok_main dmain  (cost= 0 . 00 .. 4 . 01  rows= 1  width= 47 ) (actual time= 0 . 009 .. 0 . 009  rows= 1  loops= 4542 )
              Index Cond: (dmain.kod_dok = "outer".kod_dok)
              Filter: ((naimp_dok)::text ~* 'ОБЙНЕО'::text)
Total runtime:  186 . 087  ms
выполняется в несколько раз быстрее. это и есть тот самый план, о котором я говорил LeXa NalBatпри наличии индексов по tdok_reg (data_reg_dok) и tdok_main (kod_dok) попытаться добиться плана
Код: plaintext
1.
2.
3.
4.
5.
6.
-> Nested Loop
   -> Index Scan tdok_reg (data_reg_dok)
      Index Cond: data_reg_dok>='2007-04-21'
      Filter: pr_dok_reg= 1  OR pr_dok_reg= 3  OR ...
   -> Index Scan tdok_main (kod_dok)
      Index Cond: kod_dok="outer".kod_dok
      Filter: naimp_dok~*'ОБЙНЕО'
из числа строк удовлетворяющих условию data_reg_dok>='2007-04-21' (10476 штук) почти все удовлетворяют дополнительному условию pr_dok_reg=1 OR pr_dok_reg=3 OR ... (10394 штуки). поэтому наверное вариант с UNION выигрыша не даст.
...
Рейтинг: 0 / 0
8 сообщений из 8, страница 1 из 1
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / загнать запрос по другой план
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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