powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / улучшить время выполнения
55 сообщений из 55, показаны все 3 страниц
улучшить время выполнения
    #38722827
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем привет.

PostgreSQL 9.2.8 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit
Имеется большая таблица hotcore.otahotel
Это таблица - партицирована по неделям.
в одной партиции около 67 млн. строк


Агрегирую некоторые данные таким запросом:
Код: sql
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.
with  t
as
(
select h.id,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

),
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
)
select	'2014-08-04'::date report_period,
			av.otahotel_id,
			tt.region_id,
			tt.city,
			tt.name,
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
		tt
		join	
		hotcore.otahotel av
		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
		group 	by 1, 2, 3, 4, 5, 6






такой план:
Код: 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.
GroupAggregate  (cost=1952985.69..2121620.44 rows=360000 width=616) (actual time=253060.708..253119.291 rows=97 loops=1)
  Buffers: shared hit=1603 read=48147
  CTE t
    ->  Limit  (cost=0.00..12.01 rows=100 width=43) (actual time=46.722..87.824 rows=100 loops=1)
          Buffers: shared hit=40 read=15
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43) (actual time=46.720..87.745 rows=100 loops=1)
                Index Cond: (olap_id >= 1234)
                Buffers: shared hit=40 read=15
  CTE tt
    ->  Nested Loop  (cost=0.00..857.24 rows=9 width=584) (actual time=86.658..702.377 rows=100 loops=1)
          Join Filter: (geo.id = ANY (r.geo_id_array))
          Rows Removed by Join Filter: 100
          Buffers: shared hit=287 read=173
          ->  Nested Loop  (cost=0.00..839.49 rows=100 width=589) (actual time=80.549..695.501 rows=100 loops=1)
                Buffers: shared hit=287 read=171
                ->  CTE Scan on t  (cost=0.00..2.00 rows=100 width=552) (actual time=46.725..88.096 rows=100 loops=1)
                      Buffers: shared hit=40 read=15
                ->  Index Scan using region_pkey on region r  (cost=0.00..8.36 rows=1 width=41) (actual time=6.059..6.069 rows=1 loops=100)
                      Index Cond: (id = t.region_id)
                      Buffers: shared hit=247 read=156
          ->  Materialize  (cost=0.00..12.76 rows=2 width=36) (actual time=0.061..0.062 rows=2 loops=100)
                Buffers: shared read=2
                ->  Seq Scan on geo  (cost=0.00..12.75 rows=2 width=36) (actual time=6.094..6.123 rows=2 loops=1)
                      Filter: (id = ANY ('{1,2}'::integer[]))
                      Rows Removed by Filter: 29
                      Buffers: shared read=2
  ->  Sort  (cost=1952116.43..1959619.91 rows=3001390 width=616) (actual time=253059.764..253066.980 rows=48394 loops=1)
        Sort Key: ('2014-08-04'::date), av.otahotel_id, tt.region_id, tt.city, tt.name, (hotcore.parity_type(av.*, 'OTA'::text))
        Sort Method: quicksort  Memory: 8472kB
        Buffers: shared hit=1603 read=48147
        ->  Nested Loop  (cost=0.00..808514.90 rows=3001390 width=616) (actual time=278.289..252390.572 rows=48394 loops=1)
              Buffers: shared hit=1592 read=48147
              ->  CTE Scan on tt  (cost=0.00..0.18 rows=9 width=584) (actual time=86.662..702.723 rows=100 loops=1)
                    Buffers: shared hit=287 read=173
              ->  Append  (cost=0.00..6446.87 rows=1615 width=64) (actual time=78.824..2492.596 rows=484 loops=100)
                    Buffers: shared hit=1101 read=47974
                    ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=572) (actual time=0.001..0.001 rows=0 loops=100)
                          Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date) AND (tt.id = otahotel_id))
                    ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.65..6446.87 rows=1614 width=64) (actual time=78.817..2492.307 rows=484 loops=100)
                          Recheck Cond: (otahotel_id = tt.id)
                          Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
                          Buffers: shared hit=1101 read=47974
                          ->  Bitmap Index Scan on otahotel_2014w32_otahotel_id_idx  (cost=0.00..68.24 rows=1614 width=0) (actual time=73.506..73.506 rows=484 loops=100)
                                Index Cond: (otahotel_id = tt.id)
                                Buffers: shared hit=185 read=537
Total runtime: 253122.049 ms



Можно как-то улучшить время выполнения.
спасибо.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38722897
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот план в чуть более удобном виде .

Таблица `otahotel_2014w32` холодная (`Buffers: shared hit=1101 read=47974`), сильно ли меняется время при повторном запуске запроса?

Если заменить именованные подзапросы на обычные (избавиться от `WITH` конструкции), будет ли план лучше?

Слияние циклами в #13 больно дорого выходит. Чтобы подобрать более вменяемый план, поиграйтесь с `enable_*` опциями на уровне сессии. Скажем, будет ли план лучше при
Код: sql
1.
SET enable_nestloop TO off;

?
Мне кажется тут хэширование будет быстрее...
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38722988
Alexius
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
best_time,

тут похоже поможет только кластеризация партиций otahotel по otahotel_id, чтобы с диска меньше читать. но другие запросы могут замедлиться.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38723001
/\/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time,

Приведите план запроса (ну и результат):

Код: sql
1.
2.
3.
4.
5.
SELECT
  COUNT(*)
FROM hotcore.otahotel av
WHERE av.report_date >='2014-08-04'
  AND av.report_date < '2014-08-11'
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38723614
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\/\,
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Aggregate  (cost=5091293.21..5091293.22 rows=1 width=0) (actual time=104026.977..104026.977 rows=1 loops=1)
  Buffers: shared hit=148549 read=3775537
  ->  Append  (cost=0.00..4924549.33 rows=66697556 width=0) (actual time=0.016..97824.052 rows=65288691 loops=1)
        Buffers: shared hit=148549 read=3775537
        ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=0) (actual time=0.001..0.001 rows=0 loops=1)
              Filter: ((report_date >= 2014-08-04::date) AND (report_date < 2014-08-11::date))
        ->  Seq Scan on otahotel_2014w32 av  (cost=0.00..4924549.33 rows=66697555 width=0) (actual time=0.014..89998.231 rows=65288691 loops=1)
              Filter: ((report_date >= 2014-08-04::date) AND (report_date < 2014-08-11::date))
              Buffers: shared hit=148549 read=3775537
Total runtime: 104027.062 ms

результат 65288691
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38723774
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovТаблица `otahotel_2014w32` холодная (`Buffers: shared hit=1101 read=47974`), сильно ли меняется время при повторном запуске запроса?

теплая работаем заметно лучше, но при работе в кеш она не попадает

vyegorovЕсли заменить именованные подзапросы на обычные (избавиться от `WITH` конструкции), будет ли план лучше?


Попробовал. Вроде получше. Почему? )

такой план (меняю id'шники, паритции - моделирую холодную работу
Код: 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.
GroupAggregate  (cost=1256835.03..2059817.12 rows=2817481 width=110) (actual time=133104.569..133174.068 rows=69 loops=1)
  Buffers: shared hit=2511 read=88374
  ->  Sort  (cost=1256835.03..1263878.73 rows=2817481 width=110) (actual time=133103.315..133110.089 rows=89284 loops=1)
        Sort Key: ('2014-08-04'::date), av.otahotel_id, h.region_id, h.city_en, geo.name, (hotcore.parity_type(av.*, 'OTA'::text))
        Sort Method: quicksort  Memory: 16927kB
        Buffers: shared hit=2511 read=88374
        ->  Nested Loop  (cost=0.00..791286.15 rows=2817481 width=110) (actual time=174.984..131925.536 rows=89284 loops=1)
              Buffers: shared hit=2511 read=88374
              ->  Nested Loop  (cost=0.00..868.26 rows=9 width=71) (actual time=0.067..3.873 rows=100 loops=1)
                    Join Filter: (geo.id = ANY (r.geo_id_array))
                    Rows Removed by Join Filter: 100
                    Buffers: shared hit=658
                    ->  Nested Loop  (cost=0.00..850.50 rows=100 width=76) (actual time=0.049..3.240 rows=100 loops=1)
                          Buffers: shared hit=656
                          ->  Limit  (cost=0.00..12.01 rows=100 width=43) (actual time=0.028..0.498 rows=100 loops=1)
                                Buffers: shared hit=54
                                ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43) (actual time=0.027..0.413 rows=100 loops=1)
                                      Index Cond: (olap_id >= 1234)
                                      Buffers: shared hit=54
                          ->  Index Scan using region_pkey on region r  (cost=0.00..8.36 rows=1 width=41) (actual time=0.015..0.024 rows=1 loops=100)
                                Index Cond: (id = h.region_id)
                                Buffers: shared hit=602
                    ->  Materialize  (cost=0.00..12.76 rows=2 width=36) (actual time=0.000..0.002 rows=2 loops=100)
                          Buffers: shared hit=2
                          ->  Seq Scan on geo  (cost=0.00..12.75 rows=2 width=36) (actual time=0.010..0.030 rows=2 loops=1)
                                Filter: (id = ANY ('{1,2}'::integer[]))
                                Rows Removed by Filter: 29
                                Buffers: shared hit=2
              ->  Append  (cost=0.00..9536.01 rows=2484 width=65) (actual time=72.658..1291.838 rows=893 loops=100)
                    Buffers: shared hit=1853 read=88374
                    ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=572) (actual time=0.001..0.001 rows=0 loops=100)
                          Filter: ((report_date >= '2014-06-30'::date) AND (report_date < '2014-07-07'::date) AND (h.id = otahotel_id))
                    ->  Bitmap Heap Scan on otahotel_2014w27 av  (cost=94.11..9536.01 rows=2483 width=65) (actual time=72.651..1291.416 rows=893 loops=100)
                          Recheck Cond: (otahotel_id = h.id)
                          Filter: ((report_date >= '2014-06-30'::date) AND (report_date < '2014-07-07'::date))
                          Buffers: shared hit=1853 read=88374
                          ->  Bitmap Index Scan on otahotel_2014w27_otahotel_id_idx  (cost=0.00..93.49 rows=2483 width=0) (actual time=67.884..67.884 rows=893 loops=100)
                                Index Cond: (otahotel_id = h.id)
                                Buffers: shared hit=190 read=815
Total runtime: 133175.297 ms



авторСлияние циклами в #13 больно дорого выходит. Чтобы подобрать более вменяемый план, поиграйтесь с `enable_*` опциями на уровне сессии. Скажем, будет ли план лучше при
Код: sql
1.
SET enable_nestloop TO off;

?


Код: sql
1.
2.
SET enable_nestloop TO off;
SET enable_bitmapscan TO off;


это пробовал - иногда чуть лучше

Alexiusbest_time,

тут похоже поможет только кластеризация партиций otahotel по otahotel_id, чтобы с диска меньше читать. но другие запросы могут замедлиться.

оставлю пока "про запас"
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38723963
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
best_timevyegorovЕсли заменить именованные подзапросы на обычные (избавиться от `WITH` конструкции), будет ли план лучше?


Попробовал. Вроде получше. Почему?

Ничего в целом не поменялось.
“Получше” потому, что `WITH` конструкции имеют защиту от оптимизаций. При переписывании с обычными подзапросами у оптимизатора развязаны руки на трансформацию запросов, проталкивание предикатов и другие плюшки.

best_timevyegorovСлияние циклами в #13 больно дорого выходит. Чтобы подобрать более вменяемый план, поиграйтесь с `enable_*` опциями на уровне сессии. Скажем, будет ли план лучше при
Код: sql
1.
SET enable_nestloop TO off;

?


Код: sql
1.
2.
SET enable_nestloop TO off;
SET enable_bitmapscan TO off;


это пробовал - иногда чуть лучше

А были ли варианты когда Hash Join использовался? Можно пример?

Ну а таблица остается “холодной” при использовании SeqScan из-за особенностей работы с кэшем. Чтобы избежать его “вымывания” для SeqScan-ов выделяется маленькая часть кэша, которая используется в цикле ( тут, стр. 10 ).

И еще — что возвращает такой запрос?
Код: sql
1.
2.
3.
SELECT * FROM pg_stat_user_tables
 WHERE relname IN ('otahotel','otahotel_2014w32','otahotel_2014w27','region')
 ORDER BY schemaname,relname;
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724160
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov,
судя по запросу вы зря ударились оптимизировать джойн до свёртки
похоже просто надо переписать на джойн после свёртки
поскольку со стороны tt тянутся поля однозначно соответствующие tt.id

будет свертка (агрегат) по полному скану -- что стоит, как описал автор, 104027.062 ms (что вдвое быстрее)
+ джойн коротких таблиц.

-------------------

если же автор хочет насладиться преимуществом limit 100, то ему вот это надо ускорять

Код: sql
1.
2.
3.
4.
                    ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.65..6446.87 rows=1614 width=64) (actual time=78.817..2492.307 rows=484 loops=100)
                          Recheck Cond: (otahotel_id = tt.id)
                          Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
                          Buffers: shared hit=1101 read=47974




-- расскажите нам, что это и зачем оно тут, если уже явно всё, какбе, отыскано "внутри", причем много дешевле:
Код: sql
1.
2.
3.
                          ->  Bitmap Index Scan on otahotel_2014w32_otahotel_id_idx  (cost=0.00..68.24 rows=1614 width=0) (actual time=73.506..73.506 rows=484 loops=100)
                                Index Cond: (otahotel_id = tt.id)
                                Buffers: shared hit=185 read=537



-- т.е. есть подозрение, что пройти рекурсивно по 100 id из tt "вручную" (в WITH RECURSIVE) будет много дешевле.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724178
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
ЗЫ, если лениво переписывать -- есть подозрение, что индекс типа otahotel_2014w32_otahotel_id_report_date_idx
(otahotel_id,report_date) вправят оптимайзеру мозги взад, но надо проверять
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724204
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--поправилvyegorov,
судя по запросу вы зря ударились оптимизировать джойн до свёртки

-------------------

если же автор хочет насладиться преимуществом limit 100, то ему вот это надо ускорять

Код: sql
1.
2.
3.
4.
                    ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.65..6446.87 rows=1614 width=64) (actual time=78.817..2492.307 rows=484 loops=100)
                          Recheck Cond: (otahotel_id = tt.id)
                          Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
                          Buffers: shared hit=1101 read=47974





Вот ради оптимизации `loops=100` и пытаюсь понять, почему оптимизатор выбирает цикл, а не хэш.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724220
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил... лениво переписывать...

Не уверен, что переписывать нужно много:

Код: sql
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.
WITH
...
tt AS (
...
),
av AS (
SELECT
  *
FROM hotcore.otahotel av
WHERE av.report_date >='2014-08-04'
  AND av.report_date < '2014-08-11'
)
select	'2014-08-04'::date report_period,
			av.otahotel_id,
			tt.region_id,
			tt.city,
			tt.name,
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
		tt
		join av on      av.otahotel_id = tt.id

		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
		group 	by 1, 2, 3, 4, 5, 6



Как-то так.
Но выбор во временные данные 65 млн строк меня смущает.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724252
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov,
не понял, зачем там хеш. тогда уж свернуть сначала, а потом джойнить. получите то, чего хотите, без затрат на джойн (это что, всю миллионную захешировать, потом поджойнить, и результат свернуть ? боец борется за разницу меж лямами [65288691, но последовательно] и килами [48394, но произвольно] )


-- тут интересно то, что эти записи (484) оптимайзер находит (внутри, по индексу) практически без затрат времени (пусть и лупнув 100) -- см. этап 18 плана по ссылке

а затем (снаружи) зачем то делает над ними же 17.
Bitmap Heap Scan on otahotel_2014w32 av
но уже теряя кучу (втрое) времени
Код: sql
1.
2.
3.
4.
 (actual time=78.817..2492.307 rows=484 loops=100)

    Recheck Cond: (otahotel_id = tt.id)
    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))


-- я не силён в таких тонкостях -- напрочь не понимаю, чем оно тут занимается. фильтровать оно могло и на проходе 18. считай бесплатно.

PS -- если бы в 18 было написано IOS -- я бы хоть что-то понял
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724265
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\,
не, я не про то.
я про 2 абсолютно разные альтернативы

1. свернуть все 65 лямов на проходе (100 секунд --см выше), потом поджойниться - выиграем вполовину, но никак не больше

или (совсем другое)

2. взять в CTE 100 id, и для каждого из них в конструкции with recursive взять свой агрегат (что оптимайзер [+-километр] и должен делать, но я как-то это плохо читаю).
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724280
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
авторно уже теряя кучу (втрое в 30 -- 2400 vs 80) времени
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724303
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--поправилvyegorov,
не понял, зачем там хеш. тогда уж свернуть сначала, а потом джойнить. получите то, чего хотите, без затрат на джойн (это что, всю миллионную захешировать, потом поджойнить, и результат свернуть ? боец борется за разницу меж лямами [65288691, но последовательно] и килами [48394, но произвольно] )
Хэшируется меньшая сторона, потом делается проход по большей. В данном случае сделать хэш для 100 записей из подзапроса и потом один раз пройти SeqScan-ом по 67 лимонам мне кажется будет быстрым, в пределах тех же 100 секунд. Я вижу 2 причины почему не используется хэш:
невозможно архитектурно (внутренние ограничения СУБД), но это гипотеза, точно не знаю что может быть такого;

перекос в статистиках/недостаточный размер гистограммы. Тут можно что-то крутить.

Что же касается “переписать” запрос — полностью согласен. Но хочется же разобраться в чем тут дело...

--поправил-- тут интересно то, что эти записи (484) оптимайзер находит (внутри, по индексу) практически без затрат времени (пусть и лупнув 100) -- см. этап 18 плана по ссылке

а затем (снаружи) зачем то делает над ними же 17.
Bitmap Heap Scan on otahotel_2014w32 av
но уже теряя кучу (втрое) времени
Код: sql
1.
2.
3.
4.
 (actual time=78.817..2492.307 rows=484 loops=100)

    Recheck Cond: (otahotel_id = tt.id)
    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))


-- я не силён в таких тонкостях -- напрочь не понимаю, чем оно тут занимается. фильтровать оно могло и на проходе 18. считай бесплатно.

PS -- если бы в 18 было написано IOS -- я бы хоть что-то понял

Это особенности работы BitmapScan-а. Сначала он идет по индексу, но возвращает для каждого блока (8Кб) содержащего искомые значения 1, или 0 в противном случае. Понятно, что после этого надо прочитать такие блоки и вытащить из них записи. Потому и получается всегда 2 (и более) этапа:

сначала несколько Bitmap Index Scan-ов;

наложение битмапов если более 1 индекса на 1-м шаге;

результирующий Bitmap Heap Scan.

Смысл в том, что если несколько индексов реляции подпадают под предикаты, по ним всем делаются проходы (Bitmap Index Scan), затем полученные битмапы логически накладываются (BitmapAnd / BitmapOr) и только потом идет обращение к записям (Bitmap Heap Scan) — быстрее выходит. Для единственного индекса такой проход выбирается, если селективность не очень. Тут подробнее .
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724335
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov,

1. люди, пишущие pdf идут строго лесом. (я не типография)

2. т.е. вы хотите сказать, что 18 -- это реально IOS ?
а потом BitmapOr с реальным произвольным доступом к 48000 записям (страницам) жрет 240 сек ? по ~5 ms на доступ? [200 в секунду -- 1200 в минуту - не маловато будет? или я где-то провираюсь ?)
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724343
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправилvyegorov,

1. люди, пишущие pdf идут строго лесом. (я не типография)

2. т.е. вы хотите сказать, что 18 -- это реально IOS ?
а потом BitmapOr с реальным произвольным доступом к 48000 записям (страницам) жрет 240 сек ? по ~5 ms на доступ? [200 в секунду -- 12000 в минуту - не маловато будет? или я где-то провираюсь ?)
бгг.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724366
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
там при ожиданиях много хуже 48к
авторrows=3001390
оптимайзер пускается на NestedLoop
-- имхо у ТС косты переставлены супротив дефолтных. или enable seqscan (и т.п.) в off-е
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724486
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovИ еще — что возвращает такой запрос?
Код: sql
1.
2.
3.
SELECT * FROM pg_stat_user_tables
 WHERE relname IN ('otahotel','otahotel_2014w32','otahotel_2014w27','region')
 ORDER BY schemaname,relname;



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
   relid    | schemaname |     relname      | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch 
------------+------------+------------------+----------+--------------+----------+---------------
 2520075393 | hotcore    | otahotel         |   227770 |            0 |        7 |             0
 3414794803 | partitions | otahotel_2014w27 |       37 |    124607613 |      155 |       1248182
 3570135254 | partitions | otahotel_2014w32 |       57 |   1105909190 |    76765 |   22468950983
 1586228924 | public     | otahotel         |      498 |    316392933 |  4034473 |       8150453
  367346872 | public     | region           |     1308 |    161067354 | 16604473 |      36259012
(5 строк)

...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724525
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
best_time
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
   relid    | schemaname |     relname      | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch 
------------+------------+------------------+----------+--------------+----------+---------------
 2520075393 | hotcore    | otahotel         |   227770 |            0 |        7 |             0
 3414794803 | partitions | otahotel_2014w27 |       37 |    124607613 |      155 |       1248182
 3570135254 | partitions | otahotel_2014w32 |       57 |   1105909190 |    76765 |   22468950983
 1586228924 | public     | otahotel         |      498 |    316392933 |  4034473 |       8150453
  367346872 | public     | region           |     1308 |    161067354 | 16604473 |      36259012
(5 строк)



Я ожидал увидеть больше колонок: тыц .
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724573
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov,

там 0 и NULL'ы - все равно важно?
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724622
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov,
могабыть оно слишком мало ожидает строк от tt ?

Код: sql
1.
2.
CTE tt
    ->  Nested Loop  (cost=0.00..857.24 rows=9 width=584) (actual time=86.658..702.377 rows=100 loops=1)


причем (что не очевидно, но вероятно) -- похоже geo.name можно извлечь уже в t коррелированным полем (или ТС ожидает там размножения имен ?) -- тогда оптимизатор будет знать, что предстоит искать в big table по 100 а не по 9 id-кам.


но то, что оно планирует Nested Loop при ожидании 3001390 rows
Код: sql
1.
Nested Loop  (cost=0.00..808514.90 rows=3001390 width=616)

-- кажется сипанным. что то подкручено с cost-ами ?
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724631
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time,

SHOW random_page_cost ; ?
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724636
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
best_timevyegorov,

там 0 и NULL'ы - все равно важно?

Хм, если там NULL-ы, то у меня вопросы:
как статистики собираются в системе вообще?

что выдаст такой запрос
Код: sql
1.
select name,setting,source from pg_settings where name ~ '^autovacuum|cost|enable';



как изменится план после запуска следующих команд
Код: sql
1.
2.
3.
4.
5.
VACUUM ANALYZE partitions.otahotel_2014w27;
VACUUM ANALYZE partitions.otahotel_2014w32;
VACUUM ANALYZE hotcore.otahotel;
VACUUM ANALYZE public.otahotel;
VACUUM ANALYZE public.region;
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724664
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправилbest_time,

SHOW random_page_cost ; ?
4
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724677
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time--поправилbest_time,

SHOW random_page_cost ; ?
4это дефолт, если не вру

тогда сразу всё прочее, как просит товарисч:

select name,setting,source from pg_settings where name ~ '^autovacuum|cost|enable';
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724712
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovbest_timevyegorov,

там 0 и NULL'ы - все равно важно?

Хм, если там NULL-ы, то у меня вопросы:
как статистики собираются в системе вообще?

что выдаст такой запрос
Код: sql
1.
select name,setting,source from pg_settings where name ~ '^autovacuum|cost|enable';



как изменится план после запуска следующих команд
Код: sql
1.
2.
3.
4.
5.
VACUUM ANALYZE partitions.otahotel_2014w27;
VACUUM ANALYZE partitions.otahotel_2014w32;
VACUUM ANALYZE hotcore.otahotel;
VACUUM ANALYZE public.otahotel;
VACUUM ANALYZE public.region;




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

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
   relid    | schemaname |     relname      | seq_scan | seq_tup_read | idx_scan | idx_tup_fetch | n_tup_ins | n_tup_upd | n_tup_del | n_tup_hot_upd | n_live_tup | n_dead_tup | last_vacuum |        last_autovacuum        | last_analyze |       last_autoanalyze        | vacuum_count | autovacuum_count | analyze_count | autoanalyze_count 
------------+------------+------------------+----------+--------------+----------+---------------+-----------+-----------+-----------+---------------+------------+------------+-------------+-------------------------------+--------------+-------------------------------+--------------+------------------+---------------+-------------------
 2520075393 | hotcore    | otahotel         |   253190 |            0 |      111 |             0 |         0 |         0 |         0 |             0 |          0 |          0 |             |                               |              |                               |            0 |                0 |             0 |                 0
 3414794803 | partitions | otahotel_2014w27 |       11 |            0 |      826 |            14 |         0 |         0 |         0 |             0 |          0 |          0 |             |                               |              |                               |            0 |                0 |             0 |                 0
 3570135254 | partitions | otahotel_2014w32 |      939 |   1779000316 |    19999 |    9976752347 |  65726055 |         0 |         0 |             0 |   65843802 |          0 |             | 2014-08-06 11:38:40.44619+00  |              | 2014-08-10 12:35:37.92968+00  |            0 |                2 |             0 |                37
 1586228924 | public     | otahotel         |    23232 |  15159936874 |  2505195 |    1166692195 |    521896 |    467107 |         0 |         22595 |    1009067 |       2421 |             | 2014-08-15 09:22:33.581164+00 |              | 2014-08-15 06:13:27.604283+00 |            0 |                5 |             0 |                 4
  367346872 | public     | region           |      661 |    104102332 | 15072071 |     126861899 |        28 |  11751186 |         0 |        591666 |     167886 |          0 |             | 2014-08-20 06:48:24.268671+00 |              | 2014-08-20 06:55:33.731531+00 |            0 |               56 |             0 |                31
(5 строк)

настройки:

Код: 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.
              name               |  setting  |       source       
---------------------------------+-----------+--------------------
 autovacuum                      | on        | default
 autovacuum_analyze_scale_factor | 0.1       | default
 autovacuum_analyze_threshold    | 50        | default
 autovacuum_freeze_max_age       | 200000000 | default
 autovacuum_max_workers          | 6         | configuration file
 autovacuum_naptime              | 60        | default
 autovacuum_vacuum_cost_delay    | 20        | default
 autovacuum_vacuum_cost_limit    | -1        | default
 autovacuum_vacuum_scale_factor  | 0.01      | configuration file
 autovacuum_vacuum_threshold     | 50        | default
 cpu_index_tuple_cost            | 0.005     | default
 cpu_operator_cost               | 0.0025    | default
 cpu_tuple_cost                  | 0.01      | default
 enable_bitmapscan               | on        | default
 enable_hashagg                  | on        | default
 enable_hashjoin                 | on        | default
 enable_indexonlyscan            | on        | default
 enable_indexscan                | on        | default
 enable_material                 | on        | default
 enable_mergejoin                | on        | default
 enable_nestloop                 | on        | default
 enable_seqscan                  | on        | default
 enable_sort                     | on        | default
 enable_tidscan                  | on        | default
 random_page_cost                | 4         | default
 seq_page_cost                   | 1         | default
 vacuum_cost_delay               | 0         | default
 vacuum_cost_limit               | 200       | default
 vacuum_cost_page_dirty          | 20        | default
 vacuum_cost_page_hit            | 1         | default
 vacuum_cost_page_miss           | 10        | default


ANALYZE - сейчас запущу
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724724
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time,

сделайте, если не сложно

Код: sql
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.
ANALYZE
with  tt --t
as
(
select h.id, NULL "name" ,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

) /*,
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
) --*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
			tt.region_id,
			tt.city,
			tt.name,
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
		tt
		join	
		hotcore.otahotel av
		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
		group 	by 1, 2, 3, 4, 5, 6


-- интересно посмотреть на то, что придумает оптимизатор про rows cost и метод
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724751
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил,

Код: sql
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.
with  tt
as
(
select h.id, NULL::TEXT "name", h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

)/*,

tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
)
*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
			tt.region_id,
			
			tt.name,
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
		tt
		join	
		hotcore.otahotel av
		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
		group 	by 1, 2, 3, 4, 5






Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
GroupAggregate  (cost=14962660.09..16753007.59 rows=4000000 width=100)
  CTE tt
    ->  Limit  (cost=0.00..12.01 rows=100 width=43)
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)
                Index Cond: (olap_id >= 1234)
  ->  Sort  (cost=14962648.07..15046020.02 rows=33348778 width=100)
        Sort Key: ('2014-08-04'::date), av.otahotel_id, tt.region_id, tt.name, (hotcore.parity_type(av.*, 'OTA'::text))
        ->  Nested Loop  (cost=0.00..8971767.25 rows=33348778 width=100)
              ->  CTE Scan on tt  (cost=0.00..2.00 rows=100 width=68)
              ->  Append  (cost=0.00..6329.56 rows=1615 width=64)
                    ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=572)
                          Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date) AND (tt.id = otahotel_id))
                    ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.61..6329.56 rows=1614 width=64)
                          Recheck Cond: (otahotel_id = tt.id)
                          Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
                          ->  Bitmap Index Scan on otahotel_2014w32_otahotel_id_idx  (cost=0.00..68.20 rows=1614 width=0)
                                Index Cond: (otahotel_id = tt.id)

...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724788
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time,

он таки упорствует
Код: sql
1.
Nested Loop  (cost=0.00..8971767.25 rows=33348778 width=100)



а что , если вместо JOIN предложить ему агрегат от where exists (план должен быть похожий, ну а вдруг он устанет упорствовать
~пимерно так~
Код: sql
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.
ANALYZE
with  tt --t
as
(
select h.id, NULL "name" ,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

) /*,
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
) --*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
/*			tt.region_id,
			tt.city,
			tt.name,
*/
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
/*		tt
		join	*/
		hotcore.otahotel av
--		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
AND EXISTS (SELECT 1 FROM tt WHERE av.otahotel_id = tt.id)
		group 	by 1, 2, 3 --, 4, 5, 6
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724803
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправилbest_time,

он таки упорствует
Код: sql
1.
Nested Loop  (cost=0.00..8971767.25 rows=33348778 width=100)



а что , если вместо JOIN предложить ему агрегат от where exists (план должен быть похожий, ну а вдруг он устанет упорствовать
~пимерно так~
Код: sql
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.
ANALYZE
with  tt --t
as
(
select h.id, NULL "name" ,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

) /*,
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
) --*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
/*			tt.region_id,
			tt.city,
			tt.name,
*/
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
/*		tt
		join	*/
		hotcore.otahotel av
--		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
AND EXISTS (SELECT 1 FROM tt WHERE av.otahotel_id = tt.id)
		group 	by 1, 2, 3 --, 4, 5, 6



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
HashAggregate  (cost=9472012.18..9482412.18 rows=40000 width=64)
  CTE tt
    ->  Limit  (cost=0.00..12.01 rows=100 width=43)
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)
                Index Cond: (olap_id >= 1234)
  ->  Nested Loop  (cost=2.25..8971768.50 rows=33348778 width=64)
        ->  HashAggregate  (cost=2.25..3.25 rows=100 width=32)
              ->  CTE Scan on tt  (cost=0.00..2.00 rows=100 width=32)
        ->  Append  (cost=0.00..6329.56 rows=1615 width=64)
              ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=572)
                    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date) AND (tt.id = otahotel_id))
              ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.61..6329.56 rows=1614 width=64)
                    Recheck Cond: (otahotel_id = tt.id)
                    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
                    ->  Bitmap Index Scan on otahotel_2014w32_otahotel_id_idx  (cost=0.00..68.20 rows=1614 width=0)
                          Index Cond: (otahotel_id = tt.id)
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724805
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил,

Может, вот так в угадайку поиграем:

Код: sql
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.
with  t
as
(
select h.id,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

),
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
)
SELECT	
  '2014-08-04'::date report_period,
  av.otahotel_id,
  (SELECT tt.region_id FROM tt WHERE tt.id = av.otahotel_id) AS region_id,
  (SELECT tt.city FROM tt WHERE tt.id = av.otahotel_id) AS city,
  (SELECT tt.name FROM tt WHERE tt.id = av.otahotel_id) AS name,
			--av.booking_window bw,
			--av.length_of_stay los,
  hotcore.parity_type(av.*, 'OTA') result,
  count(av.id) checks,
  sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
FROM hotcore.otahotel av
WHERE av.report_date >='2014-08-04'
  AND av.report_date < '2014-08-11'
  AND av.otahotel_id IN (SELECT id FROM tt)
GROUP BY 1, 2, 3, 4, 5, 6
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724810
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\,
вот да, тоже интересно
хотя планы не должны разниться с джойном
чо ж оно так упирается ?
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724815
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\,

ЗЫ а корреляты кошерно таки прикручивать после агрегации, а не в процессе. так оно дешевле.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724823
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил,

Я исхожу из того, что проще пробежаться по одной табличке и что-то отфильтровать, вместо того, чтобы что-то соединить по условию и потом все равно фильтровать. Достаточно часто бывает удачно.

В моем варианте соединения быть не должно. Так, пара-тройка значений отобрана уже в память (где-то 100 значений) и больше не рассчитывается.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724826
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил/\/\/\/\/\/\,

ЗЫ а корреляты кошерно таки прикручивать после агрегации, а не в процессе. так оно дешевле.

Насколько я здесь вижу, они - часть условия агрегации. То есть все равно агрегация на последнем этапе должна быть.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724831
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--поправилон таки упорствует
Код: sql
1.
Nested Loop  (cost=0.00..8971767.25 rows=33348778 width=100)



а что , если вместо JOIN предложить ему агрегат от where exists (план должен быть похожий, ну а вдруг он устанет упорствовать
~пимерно так~

Оценки дикие конечно. Вот эта
Код: sql
1.
Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)

тоже непонятна. Оптимизатор выбирает проход по индексу при возврате 1М записей, что соответствует размеру всей таблицы.

best_time, а покажите пожалуйста план для
Код: sql
1.
SET enable_nestloop TO off;



Вместе с вариантом `EXISTS` конечно же.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724832
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\--поправил,
<>

В моем варианте соединения быть не должно. Так, пара-тройка значений отобрана уже в память (где-то 100 значений) и больше не рассчитывается. у in в пж обычно план как у join , а у NOT IN -- как у ANTI JOIN (LEFT JOIN ...WHERE ...NULL) -- если не врёт память
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724835
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\,

Эм. Я пошел по формальному пути. Верю исходному запросу.
А вообще да, эти поля можно прикрутить в последнюю очередь.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724837
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
/\/\/\/\/\/\--поправил,

Может, вот так в угадайку поиграем:

Код: sql
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.
with  t
as
(
select h.id,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

),
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
)
SELECT	
  '2014-08-04'::date report_period,
  av.otahotel_id,
  (SELECT tt.region_id FROM tt WHERE tt.id = av.otahotel_id) AS region_id,
  (SELECT tt.city FROM tt WHERE tt.id = av.otahotel_id) AS city,
  (SELECT tt.name FROM tt WHERE tt.id = av.otahotel_id) AS name,
			--av.booking_window bw,
			--av.length_of_stay los,
  hotcore.parity_type(av.*, 'OTA') result,
  count(av.id) checks,
  sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
FROM hotcore.otahotel av
WHERE av.report_date >='2014-08-04'
  AND av.report_date < '2014-08-11'
  AND av.otahotel_id IN (SELECT id FROM tt)
GROUP BY 1, 2, 3, 4, 5, 6



Код: 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.
HashAggregate  (cost=29405961.41..29440661.41 rows=40000 width=64)
  CTE t
    ->  Limit  (cost=0.00..12.01 rows=100 width=43)
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)
                Index Cond: (olap_id >= 1234)
  CTE tt
    ->  Nested Loop  (cost=0.00..857.24 rows=9 width=584)
          Join Filter: (geo.id = ANY (r.geo_id_array))
          ->  Nested Loop  (cost=0.00..839.49 rows=100 width=589)
                ->  CTE Scan on t  (cost=0.00..2.00 rows=100 width=552)
                ->  Index Scan using region_pkey on region r  (cost=0.00..8.36 rows=1 width=41)
                      Index Cond: (id = t.region_id)
          ->  Materialize  (cost=0.00..12.76 rows=2 width=36)
                ->  Seq Scan on geo  (cost=0.00..12.75 rows=2 width=36)
                      Filter: (id = ANY ('{1,2}'::integer[]))
  ->  Nested Loop  (cost=0.20..28654744.64 rows=33348778 width=64)
        ->  HashAggregate  (cost=0.20..0.29 rows=9 width=32)
              ->  CTE Scan on tt  (cost=0.00..0.18 rows=9 width=32)
        ->  Append  (cost=0.00..6446.87 rows=1615 width=64)
              ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=572)
                    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date) AND (tt.id = otahotel_id))
              ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.65..6446.87 rows=1614 width=64)
                    Recheck Cond: (otahotel_id = tt.id)
                    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
                    ->  Bitmap Index Scan on otahotel_2014w32_otahotel_id_idx  (cost=0.00..68.24 rows=1614 width=0)
                          Index Cond: (otahotel_id = tt.id)
        SubPlan 3
          ->  CTE Scan on tt  (cost=0.00..0.20 rows=1 width=4)
                Filter: (id = av.otahotel_id)
        SubPlan 4
          ->  CTE Scan on tt  (cost=0.00..0.20 rows=1 width=516)
                Filter: (id = av.otahotel_id)
        SubPlan 5
          ->  CTE Scan on tt  (cost=0.00..0.20 rows=1 width=32)
                Filter: (id = av.otahotel_id)
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724841
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov <>Оценки дикие конечно.

<>Оптимизатор выбирает проход по индексу при возврате 1М записей, что соответствует размеру всей таблицы.


да единственное что напрашивается -- enable-ы и cost-ы получены не совсем в том сеансе, что вот эти вот планы.
а в том, где планы -- там все несколько иначе выставлено.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724842
/\/\/\/\/\/\
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил... обычно план...

Когда "обычно" - проблем никаких. Не очень обращал внимание.
А вот когда не обычно... Оптимизатор такие чудеса откаблучивает.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724843
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov--поправилон таки упорствует
Код: sql
1.
Nested Loop  (cost=0.00..8971767.25 rows=33348778 width=100)



а что , если вместо JOIN предложить ему агрегат от where exists (план должен быть похожий, ну а вдруг он устанет упорствовать
~пимерно так~

Оценки дикие конечно. Вот эта
Код: sql
1.
Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)

тоже непонятна. Оптимизатор выбирает проход по индексу при возврате 1М записей, что соответствует размеру всей таблицы.

best_time, а покажите пожалуйста план для
Код: sql
1.
SET enable_nestloop TO off;



Вместе с вариантом `EXISTS` конечно же.

Код: sql
1.
SET enable_nestloop TO off;




Код: sql
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.
with  tt --t
as
(
select h.id, NULL "name" ,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

) /*,
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
) --*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
/*			tt.region_id,
			tt.city,
			tt.name,
*/
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
/*		tt
		join	*/
		hotcore.otahotel av
--		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
AND EXISTS (SELECT 1 FROM tt WHERE av.otahotel_id = tt.id)
		group 	by 1, 2, 3 --, 4, 5, 6
		




Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
HashAggregate  (cost=14308077.00..14318477.00 rows=40000 width=64)
  CTE tt
    ->  Limit  (cost=0.00..12.01 rows=100 width=43)
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)
                Index Cond: (olap_id >= 1234)
  ->  Hash Semi Join  (cost=3.25..13807833.31 rows=33348778 width=64)
        Hash Cond: (av.otahotel_id = tt.id)
        ->  Append  (cost=0.00..4924549.33 rows=66697556 width=64)
              ->  Seq Scan on otahotel av  (cost=0.00..0.00 rows=1 width=572)
                    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
              ->  Seq Scan on otahotel_2014w32 av  (cost=0.00..4924549.33 rows=66697555 width=64)
                    Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
        ->  Hash  (cost=2.00..2.00 rows=100 width=32)
              ->  CTE Scan on tt  (cost=0.00..2.00 rows=100 width=32)

...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724853
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил,
а если тупо вписать otahotel_2014w32 вместо otahotel ?
план не поменяется ?
-- может быть он[, оптимайзер бишь 9.2.8,] аппендить при хешджойне не обучен ?
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724855
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил--поправил,
а если тупо вписать otahotel_2014w32 вместо otahotel ?
план не поменяется ?
-- может быть он[, оптимайзер бишь 9.2.8,] аппендить при хешджойне не обучен ?
Код: sql
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.
--SET enable_nestloop TO on;

with  tt --t
as
(
select h.id, NULL "name" ,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

) /*,
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
) --*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
/*			tt.region_id,
			tt.city,
			tt.name,
*/
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
/*		tt
		join	*/
		partitions.otahotel_2014w32 av
--		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
AND EXISTS (SELECT 1 FROM tt WHERE av.otahotel_id = tt.id)
		group 	by 1, 2, 3 --, 4, 5, 6
		



Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
HashAggregate  (cost=677350.18..719308.46 rows=161378 width=572)
  CTE tt
    ->  Limit  (cost=0.00..12.01 rows=100 width=43)
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43)
                Index Cond: (olap_id >= 1234)
  ->  Nested Loop  (cost=70.86..674917.50 rows=161378 width=572)
        ->  HashAggregate  (cost=2.25..3.25 rows=100 width=32)
              ->  CTE Scan on tt  (cost=0.00..2.00 rows=100 width=32)
        ->  Bitmap Heap Scan on otahotel_2014w32 av  (cost=68.61..6329.56 rows=1614 width=572)
              Recheck Cond: (otahotel_id = tt.id)
              Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
              ->  Bitmap Index Scan on otahotel_2014w32_otahotel_id_idx  (cost=0.00..68.20 rows=1614 width=0)
                    Index Cond: (otahotel_id = tt.id)

...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724856
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--поправил,

Было бы интересно глянуть на план в 9.3. Хотя бы только на один запрос по этим 4 таблицам...
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724862
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time,
ну вот раньше 16469948 выяснилось, что таки обучен
Код: sql
1.
 ->  Hash Semi Join  (cost=3.25..13807833.31 rows=33348778 width=64)


но оценивает в 1.5 раза дороже чем Nested Loop

Приведите EXPLAIN ANALYZE этого случая [да и извиняюсь за описки и одумки -- невнимательность]
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724871
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил,

Код: sql
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.
SET enable_nestloop TO off;
EXPLAIN ANALYZE 
with  tt --t
as
(
select h.id, NULL "name" ,h.olap_id,h.region_id,city_en
from
public.otahotel h
where olap_id>=1234
order by olap_id
limit 100

) /*,
tt as
(
select t.id,geo.name,region_id,city_en city
from t
join	public.region r
on	t.region_id = r.id
join	static.geo geo
on	geo.id = any(r.geo_id_array)
and geo.id in (1,2)
) --*/
select	'2014-08-04'::date report_period,
			av.otahotel_id,
/*			tt.region_id,
			tt.city,
			tt.name,
*/
			--av.booking_window bw,
			--av.length_of_stay los,
			hotcore.parity_type(av.*, 'OTA') result,
			count(av.id) checks,
			sum(case when av.otahotel_price != 0 then 1 else 0 end) avail		
		from
/*		tt
		join	*/
		partitions.otahotel_2014w32 av
--		on      av.otahotel_id = tt.id
		where	av.report_date >='2014-08-04'
			and av.report_date < '2014-08-11'
AND EXISTS (SELECT 1 FROM tt WHERE av.otahotel_id = tt.id)
		group 	by 1, 2, 3 --, 4, 5, 6
		




Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
HashAggregate  (cost=5144206.17..5186164.45 rows=161378 width=572) (actual time=200841.046..200841.480 rows=97 loops=1)
  CTE tt
    ->  Limit  (cost=0.00..12.01 rows=100 width=43) (actual time=0.025..0.150 rows=100 loops=1)
          ->  Index Scan using inx_u_otahotel_olap_id on otahotel h  (cost=0.00..121090.78 rows=1007859 width=43) (actual time=0.023..0.135 rows=100 loops=1)
                Index Cond: (olap_id >= 1234)
  ->  Hash Semi Join  (cost=3.25..5141773.49 rows=161378 width=572) (actual time=60.041..200715.451 rows=48394 loops=1)
        Hash Cond: (av.otahotel_id = tt.id)
        ->  Seq Scan on otahotel_2014w32 av  (cost=0.00..4924549.33 rows=66697555 width=572) (actual time=9.375..187810.465 rows=65288691 loops=1)
              Filter: ((report_date >= '2014-08-04'::date) AND (report_date < '2014-08-11'::date))
        ->  Hash  (cost=2.00..2.00 rows=100 width=32) (actual time=0.291..0.291 rows=100 loops=1)
              Buckets: 1024  Batches: 1  Memory Usage: 6kB
              ->  CTE Scan on tt  (cost=0.00..2.00 rows=100 width=32) (actual time=0.030..0.250 rows=100 loops=1)
Total runtime: 200843.223 ms

...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724880
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
best_time,
да, пожалуй он мало ошибается (2-3 -- допустимо для сложных запросов).
т.ч. [намного] лучше уже не будет.

ещё выкиньте всё ненужное из агрегата (например константу -- первое поле) -- прикрутите после. -- немного сэкономите работу оптимайзеру. (каким бы путём не пошли).
А всю расшифровку прикрутите после свертки.
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724915
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
--поправил1. свернуть все 65 лямов на проходе (100 секунд --см выше), потом поджойниться - выиграем вполовину, но никак не больше

или (совсем другое)

2. взять в CTE 100 id, и для каждого из них в конструкции with recursive взять свой агрегат (что оптимайзер [+-километр] и должен делать, но я как-то это плохо читаю).

Первый вариант выглядит оптимальным и выигрыш вполне себе хороший. Второй был представлен ТС в начальном посте (и я на нем зациклился).
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724928
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorov--поправил1. свернуть все 65 лямов на проходе (100 секунд --см выше), потом поджойниться - выиграем вполовину, но никак не больше

или (совсем другое)

2. взять в CTE 100 id, и для каждого из них в конструкции with recursive взять свой агрегат (что оптимайзер [+-километр] и должен делать, но я как-то это плохо читаю).

Первый вариант выглядит оптимальным и выигрыш вполне себе хороший. Второй был представлен ТС в начальном посте (и я на нем зациклился).скорее всего тоже выйдет все 200сек с гаком - там ф-я неизвестной стоимости [hotcore.parity_type(av.*, 'OTA') result] 65млн раз посчитается -- по ней, в частности, свертка. не факт, что она immutable
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38724935
--поправил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
--поправил,
а даже если и имутабна - записи-то все разные
бгг
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38726119
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
всем спасибо!

Выкинул функцию.
Стал считать по всей партиции. Укладываюсь вроде в 10 мин.
Меня это устраивает.
(если и завтра будет будет 10 мин )
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38726139
Фотография vyegorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
best_timeУкладываюсь вроде в 10 мин.
Изначально ж было чуть более 4 минут всего?
...
Рейтинг: 0 / 0
улучшить время выполнения
    #38726725
best_time
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
vyegorovbest_timeУкладываюсь вроде в 10 мин.
Изначально ж было чуть более 4 минут всего?

так только 100 строк. Теперь все, как Вы и советовали.
...
Рейтинг: 0 / 0
55 сообщений из 55, показаны все 3 страниц
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / улучшить время выполнения
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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