2017-01-10 17 views
0

У меня есть большой стол, foos, разделенный на foo_type. Ниже дает хороший план запроса (только один раздел, выбранный):Как получить хороший план запроса без выбора разделов литеральным значением?

select count(*) from foos where foo_type=1; 

Но если я пытаюсь изменить буквальное «1» к (эквивалент) подзапроса - я заканчиваю с планом, который сканирует каждый раздел -

select count(*) from foos where foo_type=(select min(foo_type) from favorite_foo_types); 

Как я могу написать запрос, который использует подзапрос в «где» п такие, как и не заканчивается до сканирования каждого раздела?

+0

Можете ли вы запустить второй запрос с объяснением анализа и включить это в вопрос? –

ответ

1

Вы не указали код, так что никто не ответил на вопрос. Короткий ответ, устранение динамических разделов работает в Greenplum, но объяснение отличается от плана, в котором предоставляется буквальное значение.

Пример:

Сначала создайте таблицу favorite_foo_types.

create table public.favorite_foo_types 
(id int, foo_type int) 
distributed by (id); 

insert into public.favorite_foo_types 
values (1, 1), (2,2), (3,3), (4,4), (5,5); 

analyze public.favorite_foo_types; 

Затем создайте свою секционированную таблицу.

create table public.foos 
(id int, foo_type int) 
distributed by (id) 
partition by list (foo_type) 
(
partition foo_1 values (1), 
partition foo_2 values (2), 
partition foo_3 values (3), 
partition foo_4 values (4), 
partition foo_5 values (5) 
); 

insert into public.foos 
select i as id, case when i between 1 and 1999 then 1 
when i between 2000 and 3999 then 2 
when i between 4000 and 5999 then 3 
when i between 6000 and 7999 then 4 
when i between 8000 and 9999 then 5 end as foo_type 
from generate_series(1,9999) as i; 

analyze public.foos; 

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

explain analyze 
select count(*) 
from public.foos 
where foo_type = 1; 

Aggregate (cost=0.00..431.07 rows=1 width=8) 
    Rows out: 1 rows with 0.722 ms to first row, 0.723 ms to end, start offset by 0.298 ms. 
    -> Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..431.07 rows=1 width=8) 
    Rows out: 2 rows at destination with 0.717 ms to first row, 0.718 ms to end, start offset by 0.299 ms. 
    -> Aggregate (cost=0.00..431.07 rows=1 width=8) 
      Rows out: Avg 1.0 rows x 2 workers. Max 1 rows (seg0) with 0.287 ms to end, start offset by 0.663 ms. 
      -> Sequence (cost=0.00..431.07 rows=1000 width=4) 
      Rows out: Avg 999.5 rows x 2 workers. Max 1000 rows (seg0) with 0.036 ms to first row, 0.215 ms to end, start offset by 0.663 ms. 
      -> Partition Selector for foos (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4) 
       Filter: foo_type = 1 
       Partitions selected: 1 (out of 5) 
       Rows out: 0 rows (seg0) with 0.004 ms to end, start offset by 0.663 ms. 
      -> Dynamic Table Scan on foos (dynamic scan id: 1) (cost=0.00..431.07 rows=1000 width=4) 
       Filter: foo_type = 1 
       Rows out: Avg 999.5 rows x 2 workers. Max 1000 rows (seg0) with 0.032 ms to first row, 0.140 ms to end, start offset by 0.667 ms. 
       Partitions scanned: Avg 1.0 (out of 5) x 2 workers. Max 1 parts (seg0). 
Slice statistics: 
    (slice0) Executor memory: 408K bytes. 
    (slice1) Executor memory: 195K bytes avg x 2 workers, 195K bytes max (seg0). 
Statement statistics: 
    Memory used: 128000K bytes 
Settings: optimizer=on 
Optimizer status: PQO version 1.650 
Total runtime: 1.162 ms 

Теперь ваш запрос:

explain analyze 
select count(*) 
from public.foos 
where foo_type=(select min(foo_type) from public.favorite_foo_types); 

Aggregate (cost=0.00..863.04 rows=1 width=8) 
    Rows out: 1 rows with 6.466 ms to end, start offset by 24 ms. 
    -> Gather Motion 2:1 (slice3; segments: 2) (cost=0.00..863.04 rows=1 width=8) 
    Rows out: 2 rows at destination with 5.415 ms to first row, 6.459 ms to end, start offset by 24 ms. 
    -> Aggregate (cost=0.00..863.04 rows=1 width=8) 
      Rows out: Avg 1.0 rows x 2 workers. Max 1 rows (seg0) with 4.514 ms to end, start offset by 24 ms. 
      -> Hash Join (cost=0.00..863.04 rows=5000 width=1) 
      Hash Cond: foos.foo_type = inner.min 
      Rows out: Avg 999.5 rows x 2 workers. Max 1000 rows (seg0) with 3.464 ms to first row, 4.441 ms to end, start offset by 24 ms. 
      Executor memory: 1K bytes avg, 1K bytes max (seg0). 
      Work_mem used: 1K bytes avg, 1K bytes max (seg0). Workfile: (0 spilling, 0 reused) 
      (seg0) Hash chain length 1.0 avg, 1 max, using 1 of 524341 buckets. 
      -> Dynamic Table Scan on foos (dynamic scan id: 1) (cost=0.00..431.10 rows=5000 width=4) 
       Rows out: Avg 999.5 rows x 2 workers. Max 1000 rows (seg0) with 0.382 ms to first row, 0.478 ms to end, start offset by 27 ms. 
       Partitions scanned: Avg 1.0 (out of 5) x 2 workers. Max 1 parts (seg0). 
      -> Hash (cost=100.00..100.00 rows=50 width=4) 
       Rows in: Avg 1.0 rows x 2 workers. Max 1 rows (seg0) with 0.197 ms to end, start offset by 27 ms. 
       -> Partition Selector for foos (dynamic scan id: 1) (cost=10.00..100.00 rows=50 width=4) 
       Filter: foos.id = min 
       Rows out: Avg 1.0 rows x 2 workers. Max 1 rows (seg0) with 0.189 ms to first row, 0.190 ms to end, start offset by 27 ms. 
       -> Broadcast Motion 1:2 (slice2) (cost=0.00..431.00 rows=2 width=4) 
         Rows out: Avg 1.0 rows x 2 workers at destination. Max 1 rows (seg0) with 0.015 ms to end, start offset by 27 ms. 
         -> Aggregate (cost=0.00..431.00 rows=1 width=4) 
         Rows out: 1 rows with 0.020 ms to end, start offset by 26 ms. 
         -> Gather Motion 2:1 (slice1; segments: 2) (cost=0.00..431.00 rows=1 width=4) 
          Rows out: 2 rows at destination with 0.009 ms to first row, 0.010 ms to end, start offset by 26 ms. 
          -> Aggregate (cost=0.00..431.00 rows=1 width=4) 
          Rows out: Avg 1.0 rows x 2 workers. Max 1 rows (seg0) with 0.079 ms to end, start offset by 25 ms. 
          -> Table Scan on favorite_foo_types (cost=0.00..431.00 rows=3 width=4) 
            Rows out: Avg 2.5 rows x 2 workers. Max 3 rows (seg0) with 0.065 ms to first row, 0.067 ms to end, start offset by 25 ms. 
Slice statistics: 
    (slice0) Executor memory: 414K bytes. 
    (slice1) Executor memory: 245K bytes avg x 2 workers, 245K bytes max (seg0). 
    (slice2) Executor memory: 253K bytes (entry db). 
    (slice3) Executor memory: 8493K bytes avg x 2 workers, 8493K bytes max (seg0). Work_mem: 1K bytes max. 
Statement statistics: 
    Memory used: 128000K bytes 
Settings: optimizer=on 
Optimizer status: PQO version 1.650 
Total runtime: 30.161 ms 

Обратите внимание в плане запроса, то есть "Dynamic Table Scan на Фоос", а затем ниже, "сканировали Перегородки: Среднее 1,0 (из 5) ». Это означает, что он динамически устранял 4 раздела и только 1 был отсканирован.

На сайте greenplum.org также есть графическая программа проверки плана, которая поможет вам ознакомиться с планом.

+0

Спасибо за объяснение! Я попытался воспроизвести эти результаты и получил план запросов, который все еще, кажется, выбирает все разделы - http://pastebin.com/yUmnS844 Возможно, различное поведение связано с различием в версии оптимизатора? – gcbenison

+0

Вы анализировали таблицы и корневой раздел? Это также может быть проблемой типа данных. Можете ли вы предоставить DDL для таблиц и точный SQL, который вы выполняете? –