Sha*_*Sha 1 postgresql indexing
在我的查询中,我只想使用精确的 where 条件调用数据。这些 where 条件是在 index.js 中创建的。但是解释显示位索引扫描。我不明白为什么。
我的查询如下所示:
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
Run Code Online (Sandbox Code Playgroud)
索引:
Metadata(org_id, keyword_type, country_or_region, campaign_id, keyword_id);
Report(org_id, country_or_region, campaign_id, keyword_id, date);
Run Code Online (Sandbox Code Playgroud)
解释分析:
"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"
Run Code Online (Sandbox Code Playgroud)
在这里,我只想调用 20 个项目。应该更有效吧?
当结果集相对于搜索条件具有高选择性(即,满足搜索条件的行的百分比很高)时,就会发生位图索引扫描。在这种情况下,规划器将计划扫描整个索引,形成一个位图,表示从磁盘上的哪些页面中提取数据(这发生在位图堆扫描步骤期间)。这比顺序扫描要好,因为它只扫描磁盘上的相关页面,跳过它知道相关数据不存在的页面。根据优化器可用的统计信息,执行索引扫描或仅索引扫描可能没有优势,但它仍然比顺序扫描更好。
为了完成问题的答案,仅索引扫描是对索引的扫描,它将拉取相关数据而无需访问实际表。这是因为相关数据已经在索引中。以这张表为例:
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
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
此查询导致索引扫描,因为它扫描 id < 100 的行的索引,然后访问磁盘上的实际表以提取查询*部分中包含的其他列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)
Run Code Online (Sandbox Code Playgroud)
这导致仅索引扫描,因为仅id请求列,并且(自然地)包含在索引中,因此无需访问磁盘上的实际表来检索其他任何内容。这节省了时间,但它的发生非常有限。
要回答您关于限制为 20 个结果的问题,限制发生在位图索引扫描发生之后,因此无论您限制为 20、40 还是其他值,运行时间仍然相同。在索引/仅索引扫描的情况下,执行器将在获取了LIMIT子句指定的足够行后停止扫描。在您的情况下,使用位图堆扫描,这是不可能的