В чем разница между индексным сканированием и индексированием только растровых изображений в PostgreSQL? - PullRequest
0 голосов
/ 12 октября 2019

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

Мой запрос выглядит следующим образом:

Select 
r.spend,
r.date,
...
from metadata m 
inner join 
report r
on m.org_id = r.org_id and m.country_or_region = r.country_or_region and m.campaign_id = r.campaign_id and m.keyword_id = r.keyword_id  
where r.org_id = 1 and m.keyword_type = 'KEYWORD'
offset 0  limit 20 

Индексы:

Metadata(org_id, keyword_type, country_or_region, campaign_id, keyword_id);
Report(org_id, country_or_region, campaign_id, keyword_id, date);

Объяснить Анализ:

"Limit  (cost=811883.21..910327.87 rows=20 width=8) (actual time=18120.268..18235.831 rows=20 loops=1)"
"  ->  Gather  (cost=811883.21..2702020.67 rows=384 width=8) (actual time=18120.267..18235.791 rows=20 loops=1)"
"        Workers Planned: 2"
"        Workers Launched: 2"
"        ->  Parallel Hash Join  (cost=810883.21..2700982.27 rows=160 width=8) (actual time=18103.440..18103.496 rows=14 loops=3)"
"              Hash Cond: (((r.country_or_region)::text = (m.country_or_region)::text) AND (r.campaign_id = m.campaign_id) AND (r.keyword_id = m.keyword_id))"
"              ->  Parallel Bitmap Heap Scan on report r  (cost=260773.11..2051875.83 rows=3939599 width=35) (actual time=552.601..8532.962 rows=3162553 loops=3)"
"                    Recheck Cond: (org_id = 479360)"
"                    Rows Removed by Index Recheck: 21"
"                    Heap Blocks: exact=20484 lossy=84350"
"                    ->  Bitmap Index Scan on idx_kr_org_date_camp  (cost=0.00..258409.35 rows=9455038 width=0) (actual time=539.329..539.329 rows=9487660 loops=1)"
"                          Index Cond: (org_id = 479360)"
"              ->  Parallel Hash  (cost=527278.08..527278.08 rows=938173 width=26) (actual time=7425.062..7425.062 rows=727133 loops=3)"
"                    Buckets: 65536  Batches: 64  Memory Usage: 2656kB"
"                    ->  Parallel Bitmap Heap Scan on metadata m  (cost=88007.61..527278.08 rows=938173 width=26) (actual time=1007.028..7119.233 rows=727133 loops=3)"
"                          Recheck Cond: ((org_id = 479360) AND ((keyword_type)::text = 'KEYWORD'::text))"
"                          Rows Removed by Index Recheck: 3"
"                          Heap Blocks: exact=14585 lossy=11054"
"                          ->  Bitmap Index Scan on idx_primary  (cost=0.00..87444.71 rows=2251615 width=0) (actual time=1014.631..1014.631 rows=2181399 loops=1)"
"                                Index Cond: ((org_id = 479360) AND ((keyword_type)::text = 'KEYWORD'::text))"
"Planning Time: 0.492 ms"
"Execution Time: 18235.879 ms"

Здесь я просто хочу назвать 20 предметов. Это должно быть более эффективным?

1 Ответ

1 голос
/ 13 октября 2019

Сканирование индекса растрового изображения происходит, когда результирующий набор будет иметь высокую степень избирательности по отношению к условиям поиска (т. Е. Имеется большой процент строк, которые удовлетворяют критериям поиска). В этом случае планировщик планирует сканировать весь индекс, формируя растровое изображение, из каких страниц на диске извлекаются данные (что происходит на этапе сканирования растрового изображения). Это лучше, чем последовательное сканирование, поскольку оно сканирует только соответствующие страницы на диске, пропуская страницы, о которых известно, что соответствующие данные не существуют. В зависимости от статистики, доступной оптимизатору, может быть не выгодно выполнять сканирование индекса или сканирование только индекса, но это все же лучше, чем последовательное сканирование.

Чтобы завершить ответ на вопрос,Сканирование только по индексу - это сканирование индекса, которое извлекает соответствующие данные, не посещая фактическую таблицу. Это потому, что соответствующие данные уже есть в индексе. Возьмем, к примеру, эту таблицу:

postgres=# create table foo (id int primary key, name text);
CREATE TABLE
postgres=# insert into foo values (generate_series(1,1000000),'foo');
INSERT 0 1000000

В столбце id этой таблицы есть индекс, и предположим, что мы вызываем следующий запрос:

postgres=# EXPLAIN ANALYZE SELECT * FROM foo WHERE id < 100;
                                                    QUERY PLAN                                                    
------------------------------------------------------------------------------------------------------------------
 Index Scan using foo_pkey on foo  (cost=0.42..10.25 rows=104 width=8) (actual time=0.012..1.027 rows=99 loops=1)
   Index Cond: (id < 100)
 Planning Time: 0.190 ms
 Execution Time: 2.067 ms
(4 rows)

Этот запросприводит к сканированию индекса, поскольку сканирует индекс для строк с идентификатором <100, а затем обращается к фактической таблице на диске, чтобы извлечь другие столбцы, включенные в часть <code>* запроса SELECT.

Однако предположим, что мы вызываем следующий запрос (уведомление SELECT id вместо SELECT *):

postgres=# EXPLAIN ANALYZE SELECT id FROM foo WHERE id < 100;
                                                      QUERY PLAN                                                       
-----------------------------------------------------------------------------------------------------------------------
 Index Only Scan using foo_pkey on foo  (cost=0.42..10.25 rows=104 width=4) (actual time=0.019..0.996 rows=99 loops=1)
   Index Cond: (id < 100)
   Heap Fetches: 99
 Planning Time: 0.098 ms
 Execution Time: 1.980 ms
(5 rows)

Это приводит к сканированию только по индексу, поскольку запрашивается только столбец id, иэто включено (естественно) в индекс, поэтому нет необходимости посещать фактическую таблицу на диске, чтобы получить что-либо еще. Это экономит время, но его появление очень ограничено.

Чтобы ответить на ваш вопрос об ограничении до 20 результатов, ограничение происходит после сканирования растровых индексов, поэтому время выполнения все равно будет тем же, независимо от того, ограничены ли вы20, 40 или какое-то другое значение. В случае сканирования по индексу / только по индексу исполнитель прекратит сканирование после того, как получит достаточно строк, как указано в предложении LIMIT. В вашем случае, с помощью растрового сканирования кучи это невозможно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...