Merge делается частями?

Gold_
Дата: 18.02.2015 17:19:39
Всем привет!

PostgreSQL 9.2.4 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit

Запрос:
select *
from hotcore.otahotel oh
join public.otahotel o on o.id = oh.otahotel_id
WHERE oh.report_date >= '2015-02-01'       
ORDER BY oh.otahotel_id
limit 10


план:
Limit  (cost=0.06..54.31 rows=10 width=1030) (actual time=0.140..108.037 rows=10 loops=1)
  Buffers: shared hit=36 read=9
  ->  Merge Join  (cost=0.06..710762203.84 rows=131020066 width=1030) (actual time=0.139..108.026 rows=10 loops=1)
        Merge Cond: (o.id = oh.otahotel_id)
        Buffers: shared hit=36 read=9
        ->  Index Scan using pk_otahotel on otahotel o  (cost=0.00..2036843.60 rows=512915 width=356) (actual time=0.017..0.044 rows=7 loops=1)
              Buffers: shared hit=15
        ->  Materialize  (cost=0.06..707086327.12 rows=131020066 width=673) (actual time=0.088..107.938 rows=10 loops=1)
              Buffers: shared hit=21 read=9
              ->  Merge Append  (cost=0.06..706758776.96 rows=131020066 width=673) (actual time=0.086..107.918 rows=10 loops=1)
                    Sort Key: oh.otahotel_id
                    Buffers: shared hit=21 read=9
                    ->  Index Scan using inx_otahotel_otahotel_id on otahotel oh  (cost=0.00..8.27 rows=1 width=556) (actual time=0.003..0.003 rows=0 loops=1)
                          Filter: (report_date >= '2015-02-01'::date)
                          Buffers: shared hit=1
                    ->  Index Scan using otahotel_2015w05_otahotel_id_idx on otahotel_2015w05 oh  (cost=0.00..226084247.23 rows=4382998 width=692) (actual time=0.017..46.545 rows=6 loops=1)
                          Filter: (report_date >= '2015-02-01'::date)
                          Buffers: shared hit=5 read=5
                    ->  Index Scan using otahotel_2015w06_otahotel_id_idx on otahotel_2015w06 oh  (cost=0.00..225204555.62 rows=59753404 width=689) (actual time=0.015..0.015 rows=1 loops=1)
                          Filter: (report_date >= '2015-02-01'::date)
                          Buffers: shared hit=5
                    ->  Index Scan using otahotel_2015w07_otahotel_id_idx on otahotel_2015w07 oh  (cost=0.00..210879381.46 rows=55944925 width=670) (actual time=0.017..0.017 rows=1 loops=1)
                          Filter: (report_date >= '2015-02-01'::date)
                          Buffers: shared hit=5
                    ->  Index Scan using otahotel_2015w08_otahotel_id_idx on otahotel_2015w08 oh  (cost=0.00..41220842.45 rows=10938738 width=599) (actual time=0.018..61.228 rows=5 loops=1)
                          Filter: (report_date >= '2015-02-01'::date)
                          Buffers: shared hit=5 read=4
Total runtime: 108.224 ms


Вопрос:
Как постгрес понял, что можно прочитать только часть строк?
(например для таблицы otahotel_2015w06 запланировал 59753404, а прочитал 1. Для otahotel запланировал 512915, прочитал 7. Запланированое соответствует количеству строк в таблицах. )
лопата
Дата: 18.02.2015 17:54:02
Gold_,

вы же лимит наложили, а он вдоль oh.otahotel_id, вдоль которого мерж--аппенд происходит. Как отъели 10 (в процессе мерджа) -- так и перестали мерджить.
а условие у вас -- партиционное -- нужные партиции, считай, все >= '2015-02-01'

Вот если вы в другом порядке лимит наложите -- тут и приплывёте.
vyegorov
Дата: 18.02.2015 18:09:03
Gold_
Всем привет!
Вопрос:
Как постгрес понял, что можно прочитать только часть строк?
(например для таблицы otahotel_2015w06 запланировал 59753404, а прочитал 1. Для otahotel запланировал 512915, прочитал 7. Запланированое соответствует количеству строк в таблицах. )

Запланировал много поскольку статистики такие. А вернул только то, что пропустил фильтр.
Gold_
Дата: 19.02.2015 13:35:28
vyegorov
Gold_
Всем привет!
Вопрос:
Как постгрес понял, что можно прочитать только часть строк?
(например для таблицы otahotel_2015w06 запланировал 59753404, а прочитал 1. Для otahotel запланировал 512915, прочитал 7. Запланированое соответствует количеству строк в таблицах. )

Запланировал много поскольку статистики такие. А вернул только то, что пропустил фильтр.


Нет. фильтр не участвовал.



лопата
Gold_,

вы же лимит наложили, а он вдоль oh.otahotel_id, вдоль которого мерж--аппенд происходит. Как отъели 10 (в процессе мерджа) -- так и перестали мерджить.
а условие у вас -- партиционное -- нужные партиции, считай, все >= '2015-02-01'

Вот если вы в другом порядке лимит наложите -- тут и приплывёте.


правильно ли я понимаю, что
на этапе чтения индексов таблиц партиций oh сначала читается по одной записи,
затем принимается решение из каких таблиц дочитать,
затем читается индекс таблицы o, пока не попадется максимальный из прочитанных из oh?
лопата
Дата: 19.02.2015 14:48:09
Gold_,

как оно работает -- я точно не читал.
полагаю, что вы излагаете почти правильно


если в плане по партицированной таблице "Merge Append", а в самом запросе -- "LIMIT" -- то оно , не смотря на "вложенность" плана, обрезается (пытается) лимитом после каждого шага мерджа. Если же ордер бай сделать поперек индексов, по которым он спланирует выбирать, то в плане будет простой (а не мердж) аппенд, потом -- сорт, и только потом -- лимит.
Т.е. тогда "унтуре" он "профетчит" всё, что "запланировал".
Alexius
Дата: 19.02.2015 15:44:27
Gold_,

вот исходники как это сделано. довольно хитро оказывается устроено.
насколько я понял, сначала действительно считывается по одному таплу из каждой subnode (если есть). дальше вот не совсем понятно, но можно предположить что в отсортированном массиве устанавливается указатель на наименьшее значение и следующий элемент читается из соответствующей subnode, результат вставляется в нужное место и указатель перемещается.
на самом деле там как-то по-другому сделано, но смысл скорее всего похожий.