PostgreSQL扫描方法综述

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介: PostgreSQL扫描方法综述

PostgreSQL扫描方法综述

 

关系型数据库都需要产生一个最佳的执行计划从而在查询时耗费的时间和资源最少。通常情况下,所有的数据库都会产生一个以树形式的执行计划:计划树的叶子节点被称为表扫描节点。查询节点对应于从基表获取数据。

例如,这一个查询:SELECT *FROM TAB1,TAB2 where TAB2.ID>1000。假设计划树如下:

 

上面的计划树:TBL1上的顺序扫描”和“TBL2上的索引扫描”分别对应于表TBL1TBL2上的表扫描方法。TBL1上的顺序扫描:从对应页中顺序获取数据;索引扫描:使用索引扫描访问表2。选择一个正确的扫描方法作为计划的一部分对于查询性能非常重要。

深入理解PG的扫描方法之前,先介绍几个重要的概念。

 

HEAP:存储表整个行的存储域。如上所示,整个域被分割为多个页,每个页大小默认是8K。每个页中,item指针(例如上述页中的1,2)指向页内的数据。

Index Storage:只存储KEY值,即索引中包含的列值。也是分割成多个页,每个索引页默认8K

Tuple Identifier(TID)TID6个字节,包含两部分。前4个字节为页号,后2个字节为页内tuple索引。TID可以定位到特定记录。

当前版本,PG支持以下扫描方法:顺序扫描、索引扫描、索引覆盖扫描、bitmap扫描、TID扫描。依赖于表基数、选择的表、磁盘IO、随机IO、顺序IO等,每种扫描方法都非常有用。我们先创建一个表并预制数据,并解释这些扫描方法。


postgres=# CREATE TABLE demotable (num numeric, id int);
CREATE TABLE
postgres=# CREATE INDEX demoidx ON demotable(num);
CREATE INDEX
postgres=# INSERT INTO demotable SELECT random() * 1000,  generate_series(1, 1000000);
INSERT 0 1000000
postgres=# analyze;
ANALYZE

这个例子中预制1亿条记录并执行analyze更新统计信息。


顺序扫描


顾名思义,表的顺序扫描就是顺序扫描对应表所有页的item指针。如果一个表有100页,每页有1000条记录,顺序扫描就会获取100*1000条记录并检查是否匹配隔离级别以及where条件。因此,即使只有1条记录满足条件,他也会扫描100K条记录。针对上表的数据,下面的查询会进行顺序扫描,因为有大部分的数据需要被selected



postgres=# explain SELECT * FROM demotable WHERE num < 21000;
                             QUERY PLAN
--------------------------------------------------------------------
 Seq Scan on demotable  (cost=0.00..17989.00 rows=1000000 width=15)
   Filter: (num < '21000'::numeric)
(2 rows)

注意,不计算和比较计划耗费,几乎不可能直到选用哪个扫描方法。但是为了使用顺序扫描,至少需要满足以下关键点:谓词部分没有可用的索引键;或者SQL查询获取的行记录占表的大部分。如果只有少数行数据被获取,并且谓词在一个或多个列上,那么久会尝试使用或者不使用索引来评估性能。


索引扫描


和顺序扫描不同,索引扫描不会顺序获取所有表记录。相反,依赖于不同索引类型并和查询中涉及的索引相对应使用不同的数据结构。然后索引扫描获取的条目直接指向heap域中的数据,然后根据隔离级别判断可见性。因此索引扫描分两步:

从索引数据结构中获取数据,返回heap中数据对应的TID;然后定位到对应的heap页直接访问数据。由于以下原因需要执行额外的步骤:查询可能请求可用索引更多的列;索引数据中不维护可见信息,为了判断可见性,需要访问heap数据。

此时可能会迷惑,索引扫描如此高效,为什么有时不用呢?原因在于cost。这里的cost涉及IO的类型。索引扫描中,为了获取heap中的对应数据,涉及随机IO;而顺序扫描涉及顺序IO,只有随机IO耗时的1/4

因此只有当顺序IO的代价大于随机IO时,才会选择索引扫描。

针对上表和数据,执行下面查询时会使用索引扫描。随机IO代价小,从而查询标记快。



postgres=# explain SELECT * FROM demotable WHERE num = 21000;
                                QUERY PLAN
--------------------------------------------------------------------------
 Index Scan using demoidx on demotable  (cost=0.42..8.44 rows=1 width=15)
   Index Cond: (num = '21000'::numeric)
(2 rows)

Index Only Scan


仅索引扫描和索引扫描类似,区别在于第二步,仅仅涉及到扫描索引数据。有两个条件:查询获取的数据只有key列,且该列是索引的一部分;所有获取的数据都是可见的。如下所示:


postgres=# explain SELECT num FROM demotable WHERE num = 21000;
                                  QUERY PLAN
-----------------------------------------------------------------------------
Index Only Scan using demoidx on demotable  (cost=0.42..8.44 rows=1 Width=11)
   Index Cond: (num = '21000'::numeric)
(2 rows)

Bitmap Scan


是索引扫描和顺序扫描的混合体。为了解决索引扫描的缺点并充分利用其优点。正如上面所说,对于索引数据结构中的数据,需要找到heap页中对应的数据。因此需要获取一次索引页,然后获取heap页,从而造成大量随机IOBitmap扫描方法平衡了不使用随机IO的索引扫描优点。

Bitmap index scan:首先获取索引数据并为所有TID创建bitmap。为了理解方法,可以认为bitmap包含所有页的哈希(基于页号),每个页的entry包含页内所有偏移的数组。

Bitmap heap scan:从页的bitmap中读取值,然后针对页和偏移扫描数据。最后检查可见性和条件并返回tuple

下面查询使用bitmap扫描,因为他选择的记录很多(比如too much for index scan)但不是大量(too little for sequential scan)。


postgres=# explain SELECT * FROM demotable WHERE num < 210;
                                  QUERY PLAN
--------------------------------------------------------------------------
 Bitmap Heap Scan on demotable  (cost=5883.50..14035.53 rows=213042 width=15)
   Recheck Cond: (num < '210'::numeric)
   ->  Bitmap Index Scan on demoidx  (cost=0.00..5830.24 rows=213042 width=0)
      Index Cond: (num < '210'::numeric)
(4 rows)

 

再看另一个查询,选择同样多的记录但是仅仅索引列。不需要heap页因次没有随机IO,因此这个查询选择index only scan而不是bitmap scan


postgres=# explain SELECT num FROM demotable WHERE num < 210;
                                   QUERY PLAN
---------------------------------------------------------------------------
 Index Only Scan using demoidx on demotable  (cost=0.42..7784.87 rows=208254 width=11)
   Index Cond: (num < '210'::numeric)
(2 rows)

TID Scan


TID扫描是PG中非常特殊的一种方式,Oracle中的基于ROWID查询类似:


postgres=# select ctid from demotable where id=21000;
   ctid
----------
 (115,42)
(1 row)
postgres=# explain select * from demotable where ctid='(115,42)';
                        QUERY PLAN
----------------------------------------------------------
 Tid Scan on demotable  (cost=0.00..4.01 rows=1 width=15)
   TID Cond: (ctid = '(115,42)'::tid)
(2 rows)

 

此外,PG社区还在讨论其他的扫描方法:MySQL中的“Loose Index Scan”、Oracle中的“index skip scan”、DB2中的“jump scan”。这个扫描方法用在指定场景:选择的B-tree索引的key列值都不同。避免遍历所有相等的key值,而只遍历第一个唯一值然后跳到下一个大值。这项工作PG正在开发,同样被叫做“Index skip scan”,未来可以在release中看到这个特性。


原文


https://severalnines.com/database-blog/overview-various-scan-methods-postgresql

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
3月前
|
SQL 关系型数据库 Linux
在CentOS 6上安装和使用PostgreSQL的方法
在CentOS 6上安装和使用PostgreSQL的方法
46 2
|
3月前
|
Ubuntu 关系型数据库 数据库
在Ubuntu 18.04上安装和使用PostgreSQL的方法
在Ubuntu 18.04上安装和使用PostgreSQL的方法
66 1
|
3月前
|
Ubuntu 关系型数据库 Linux
在Ubuntu 14.04上安装和使用PostgreSQL的方法
在Ubuntu 14.04上安装和使用PostgreSQL的方法
48 1
|
3月前
|
关系型数据库 Linux 数据库
在CentOS 7上安装和使用PostgreSQL的方法
在CentOS 7上安装和使用PostgreSQL的方法
324 0
|
6月前
|
SQL 关系型数据库 MySQL
postgresql |数据库 |数据库的常用备份和恢复方法总结
postgresql |数据库 |数据库的常用备份和恢复方法总结
243 0
|
SQL NoSQL 关系型数据库
PostgreSQL 准确且快速的数据对比方法
作为一款强大而广受欢迎的开源关系型数据库管理系统,PostgreSQL 在数据库领域拥有显著的市场份额。其出色的可扩展性、稳定性使其成为众多企业和项目的首选数据库。而在很多场景下(开发 | 生产环境同步、备份恢复验证、数据迁移、数据合并等),不同环境中的数据库数据可能导致数据的不一致,因此,进行数据库之间的数据对比变得至关重要。
360 0
|
存储 关系型数据库 PostgreSQL
PostgreSQL表扫描方法解析
PostgreSQL表扫描方法解析
127 0
|
存储 NoSQL 关系型数据库
PostgreSQL 12的可拔插存储引擎--表访问方法以及bloackholes案例
PostgreSQL 12的可拔插存储引擎--表访问方法以及bloackholes案例
175 0
|
关系型数据库 分布式数据库 PolarDB
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
365 0
|
存储 缓存 关系型数据库
下一篇
无影云桌面