AnalyticDB for PostgreSQL 6 新特性解析 - Index Only Scan

本文涉及的产品
RDS PostgreSQL Serverless,0.5-4RCU 50GB 3个月
推荐场景:
对影评进行热评分析
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介: PG中所有的索引都是二级索引,即在进行索引查询的过程中,需要同时访问索引数据和源表数据。Index Only Scan按照字面意思理解,即在查询过程中只需要扫描索引数据。这种扫描方式需要一个前提就是索引中包含了查询所需要的所有数据(也叫覆盖索引),如出现在SELECT, WHERE, ORDER BY中所引用的列。

原理介绍

PG中所有的索引都是二级索引,即在进行索引查询的过程中,需要同时访问索引数据和源表数据。Index Only Scan按照字面意思理解,即在查询过程中只需要扫描索引数据。这种扫描方式需要一个前提就是索引中包含了查询所需要的所有数据(也叫覆盖索引),如出现在SELECT, WHERE, ORDER BY中所引用的列。

由于PG的MVCC机制,在没有Index only scan之前,任何索引查询都需要经过通过源表数据进行可见性检查,如图所示:

1

在索引扫描到过程中,需要通过源表获取每个Record的可见性信息。
在PG9.2版本以后,支持了Index Only Scan,如果一个查询所需要的数据能够完全可以被索引覆盖,那么Index Only Scan就会成为一种新的扫描路径,并且通过Visibility map避免了通过获取源表进行可见性检查,提升了查询性能,如果所示:

2

这里主要依赖了Visibility map的机制,Visibility map中有一个标记位,标记了Page中的元组是否都是可见的,也就意味着如果表没有被delete、update过或者已经被vacuum过了。
如果Visibility map能够确认该Index entry所对应的Page都是可见的,那么就不再获取源表Record进行可见性判断了,否则还需要获取源表元组并进行可见性判断。

使用示例

GP6版本集成了PG9.4版本,因此也支持了Index Only Scan的特性。
例如存在一张表,并在其中一个列上创建了索引:

postgres=# \d customer_reviews_hp
         Table "public.customer_reviews_hp"
        Column        |      Type       | Modifiers
----------------------+-----------------+-----------
 customer_id          | text            |
 review_date          | date            |
 review_rating        | integer         |
 review_votes         | integer         |
 review_helpful_votes | integer         |
 product_id           | character(10)   |
 product_title        | text            |
 product_sales_rank   | bigint          |
 product_group        | text            |
 product_category     | text            |
 product_subcategory  | text            |
 similar_product_ids  | character(10)[] |
Indexes:
    "c_review_rating" btree (review_rating)
Distributed by: (customer_id)

查询:

postgres=# explain analyze select count(*), review_rating from customer_reviews_hp where review_rating > 1 group by 2;
                                                                                       QUERY PLAN

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------
 Gather Motion 4:1  (slice2; segments: 4)  (cost=49979.36..49979.50 rows=5 width=12) (actual time=782.673..782.726 rows=4 loops=1)
   ->  GroupAggregate  (cost=49979.36..49979.50 rows=2 width=12) (actual time=782.384..782.385 rows=2 loops=1)
         Group Key: customer_reviews_hp.review_rating
         ->  Sort  (cost=49979.36..49979.37 rows=2 width=12) (actual time=782.376..782.377 rows=8 loops=1)
               Sort Key: customer_reviews_hp.review_rating
               Sort Method:  quicksort  Memory: 132kB
               ->  Redistribute Motion 4:4  (slice1; segments: 4)  (cost=0.18..49979.30 rows=2 width=12) (actual time=76.538..782.345 rows=8 loops=1)
                     Hash Key: customer_reviews_hp.review_rating
                     ->  GroupAggregate  (cost=0.18..49979.20 rows=2 width=12) (actual time=5.102..73.709 rows=4 loops=1)
                           Group Key: customer_reviews_hp.review_rating
                           ->  Index Only Scan using c_review_rating on customer_reviews_hp  (cost=0.18..41742.09 rows=411854 width=4) (actual time=0.128..643.718 rows=1061311 lo
ops=1)
                                 Index Cond: (review_rating > 1)
                                 Heap Fetches: 0
 Planning time: 0.212 ms
   (slice0)    Executor memory: 220K bytes.
   (slice1)    Executor memory: 156K bytes avg x 4 workers, 156K bytes max (seg0).
   (slice2)    Executor memory: 92K bytes avg x 4 workers, 92K bytes max (seg0).  Work_mem: 33K bytes max.
 Memory used:  2047000kB
 Optimizer: Postgres query optimizer
 Execution time: 783.308 ms
(20 rows)

由此可见启用了Index Only Scan。

可以通过enable_indexonlyscan来控制是否使用Index Only Scan,例如同样上面的查询设置enable_indexonlyscan为off后,再次执行:

postgres=# explain analyze select count(*), review_rating from customer_reviews_hp where review_rating > 1 group by 2;
                                                                                     QUERY PLAN

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--
 Gather Motion 4:1  (slice2; segments: 4)  (cost=49979.36..49979.50 rows=5 width=12) (actual time=951.830..951.840 rows=4 loops=1)
   ->  GroupAggregate  (cost=49979.36..49979.50 rows=2 width=12) (actual time=951.566..951.567 rows=2 loops=1)
         Group Key: customer_reviews_hp.review_rating
         ->  Sort  (cost=49979.36..49979.37 rows=2 width=12) (actual time=951.556..951.556 rows=8 loops=1)
               Sort Key: customer_reviews_hp.review_rating
               Sort Method:  quicksort  Memory: 132kB
               ->  Redistribute Motion 4:4  (slice1; segments: 4)  (cost=0.18..49979.30 rows=2 width=12) (actual time=75.010..951.527 rows=8 loops=1)
                     Hash Key: customer_reviews_hp.review_rating
                     ->  GroupAggregate  (cost=0.18..49979.20 rows=2 width=12) (actual time=5.211..77.359 rows=4 loops=1)
                           Group Key: customer_reviews_hp.review_rating
                           ->  Index Scan using c_review_rating on customer_reviews_hp  (cost=0.18..41742.09 rows=411854 width=4) (actual time=0.118..817.460 rows=1061311 loops=1
)
                                 Index Cond: (review_rating > 1)
 Planning time: 0.217 ms
   (slice0)    Executor memory: 156K bytes.
   (slice1)    Executor memory: 92K bytes avg x 4 workers, 92K bytes max (seg0).
   (slice2)    Executor memory: 92K bytes avg x 4 workers, 92K bytes max (seg0).  Work_mem: 33K bytes max.
 Memory used:  2047000kB
 Optimizer: Postgres query optimizer
 Execution time: 952.473 ms
(19 rows)

只是用到了索引,不是Index Only Scan,执行时间上增加了将近200ms,下降了20%左右。
但同时需要注意的是,Index Only Scan并不是银弹,做到Index Only Scan往往需要创建联合索引,联合索引本身也会有性能问题,例如影响写入、更新性能等。需要具体问题具体分析,Index Only Scan只是多了一种可优化路径选择。

GP的限制

  1. Orca优化器不支持Index Only Scan,GP6版本中,只有PG原生的优化器支持Index Only Scan。
  2. 列存表也不支持Index Only Scan,Index Only Scan依赖Visibility map机制实现,列存表显然做不到Index Only Scan。
  3. GP上的Index Only Scan在explain analyze时,Heap Fetches显示不准确,例如:
create table test (a , b ,c);
create table test (a int, b int ,c int);
insert into test values(generate_series(1,100000),generate_series(1,100000),generate_series(1,100000));
create index a_ind on test(a,b,c);

-- Master上执行:
postgres=# explain analyze select * from test where a > 1 order by a;
                                                             QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
 Gather Motion 1:1  (slice1; segments: 1)  (cost=0.17..2463.87 rows=99990 width=12) (actual time=1.169..84.196 rows=99999 loops=1)
   Merge Key: a
   ->  Index Only Scan using a_ind on test  (cost=0.17..2463.87 rows=99990 width=12) (actual time=0.116..44.373 rows=99999 loops=1)
         Index Cond: (a > 1)
         Heap Fetches: 0
 Planning time: 0.685 ms
   (slice0)    Executor memory: 216K bytes.
   (slice1)    Executor memory: 148K bytes (seg0).
 Memory used:  128000kB
 Optimizer: Postgres query optimizer
 Execution time: 96.809 ms
(11 rows)

显示Heap Fetchs为0,而直接连上segment进行explain analyze:

postgres=# explain analyze select * from test where a > 1 order by a;
                                                          QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using a_ind on test  (cost=0.29..1255.62 rows=33334 width=12) (actual time=0.072..39.561 rows=99999 loops=1)
   Index Cond: (a > 1)
   Heap Fetches: 99999
 Planning time: 0.148 ms
   (slice0)
 Optimizer: Postgres query optimizer
 Execution time: 47.481 ms
(7 rows)

其实是存在Heap Fetches的,从执行时间上看,Master上的Heap Fetches项显示不对。
这种情况需要依赖Vacuum来做Visibility Map的清理工作了。正常情况下做下Vacuum analyze就能保证不不需要Heap Fetch。

参考

https://www.postgresql.org/docs/current/indexes-index-only-scans.html

相关实践学习
AnalyticDB MySQL海量数据秒级分析体验
快速上手AnalyticDB MySQL,玩转SQL开发等功能!本教程介绍如何在AnalyticDB MySQL中,一键加载内置数据集,并基于自动生成的查询脚本,运行复杂查询语句,秒级生成查询结果。
阿里云云原生数据仓库AnalyticDB MySQL版 使用教程
云原生数据仓库AnalyticDB MySQL版是一种支持高并发低延时查询的新一代云原生数据仓库,高度兼容MySQL协议以及SQL:92、SQL:99、SQL:2003标准,可以对海量数据进行即时的多维分析透视和业务探索,快速构建企业云上数据仓库。 了解产品 https://www.aliyun.com/product/ApsaraDB/ads
目录
相关文章
|
4月前
|
缓存 编译器 测试技术
PHP 8新特性解析与应用
在软件开发的广阔天地中,PHP始终是一颗耀眼的星辰。随着PHP 8的发布,一系列激动人心的新特性为开发者带来了前所未有的编程体验。本文将深入探讨PHP 8中的JIT编译器、联合类型、命名参数、匹配表达式等关键特性,并通过实例分析它们如何优化代码结构、提升执行效率。我们将一起见证PHP 8如何开启现代化PHP开发的新篇章,并为读者提供实用的技术参考。
36 2
|
20天前
|
监控 数据挖掘 OLAP
深入解析:AnalyticDB中的高级查询优化与性能调优
【10月更文挑战第22天】 AnalyticDB(ADB)是阿里云推出的一款实时OLAP数据库服务,它能够处理大规模的数据分析任务,提供亚秒级的查询响应时间。对于已经熟悉AnalyticDB基本操作的用户来说,如何通过查询优化和性能调优来提高数据处理效率,是进一步提升系统性能的关键。本文将从个人的角度出发,结合实际经验,深入探讨AnalyticDB中的高级查询优化与性能调优技巧。
59 4
|
4月前
|
安全 编译器 测试技术
PHP 8新特性解析与应用实践
本文深入探讨了PHP 8的新颖特性,并结合数据和案例分析,展示了这些新特性如何在实际开发中提升代码质量和执行效率。文章不仅涵盖了语言层面的更新,如JIT编译器和联合类型,还讨论了生态系统中的改进,例如改进的错误处理和性能优化技巧。通过逻辑严密的分析,本文旨在为读者提供一份关于PHP 8升级和应用的全面指南。
37 0
|
4月前
|
存储 SQL 编译器
PHP 8新特性深度解析与实战应用
本文将深入探讨PHP 8的新增特性,并结合实际案例演示如何有效利用这些特性优化现有项目。通过本文,您将了解到PHP 8带来的性能提升、安全性增强以及代码简化等方面的改进,以及如何将这些新特性融入日常开发工作之中。 【7月更文挑战第29天】
52 8
|
4月前
|
缓存 安全 测试技术
深入PHP 7:新特性与性能提升解析
在PHP 7的发布中,我们见证了一系列令人兴奋的性能改进和新特性的加入。本文将深入探讨这些变化如何影响开发者的日常编程实践,并展示通过实际例子如何最大化利用PHP 7的优势。准备好迎接代码效率和开发体验的全新升级!
|
4月前
|
大数据 编译器 API
PHP 7新特性深度解析与应用实践
【7月更文挑战第28天】本文深入探讨PHP 7带来的革新特性,从性能优化到语法改进,逐一剖析其背后的技术原理和实际影响。通过实例展示如何有效利用这些新特性来提升开发效率和代码质量,为PHP开发者提供切实可行的升级和优化策略。
|
4月前
|
数据挖掘 编译器 PHP
PHP 8新特性解析及其对现代Web开发的影响
随着PHP 8的发布,这一广泛使用的服务器端脚本语言带来了一系列创新特性,旨在提升性能、增强语法的易用性以及支持最新的编程范式。本文将深入探讨PHP 8中的JIT编译器、联合类型、匹配表达式等关键特性,并通过实际案例分析它们如何优化代码结构、提高执行效率,并简化日常开发工作,从而全面评估PHP 8对现代Web开发实践的深远影响。
|
4月前
|
安全 编译器 测试技术
PHP 8新特性解析与实践
作为一门历史悠久的脚本语言,PHP在近期发布的PHP 8版本中引入了诸多令人振奋的新特性。本篇文章将深入探讨这些新特性,包括JIT编译器、联合类型、命名参数、匹配表达式等,并结合实际代码示例,展示如何在项目中应用这些新功能来提升开发效率和代码质量。
|
4月前
|
算法 编译器 数据处理
PHP 8新特性深度解析与应用实践
本文旨在深入探讨PHP 8的新增特性,并指导如何将这些特性应用于实际开发中。文章将重点介绍JIT编译器、联合类型、命名参数、匹配表达式等关键改进,并通过实例展示它们如何提升代码性能和可读性。读者将了解到这些特性背后的设计哲学及其对PHP未来发展方向的影响。
37 1
|
4月前
|
安全 编译器 数据处理
PHP 8:新特性解析与实践应用
本文深入探讨了PHP 8版本中引入的关键新特性,包括JIT编译器、联合类型、命名参数、匹配表达式等,并结合实例代码演示了如何在实际项目中有效利用这些新功能来提高开发效率和代码质量。通过对比分析PHP 7与PHP 8的性能差异,文章进一步验证了新版本带来的性能提升,旨在为PHP开发者提供升级至PHP 8的全面指南。
50 2

热门文章

最新文章

相关产品

  • 云数据库 RDS PostgreSQL 版