为何PostgreSQL没有聚集索引?解读两大数据库的设计差异

前言

高效的数据检索是数据库管理的基石, PostgreSQL和SQL Server都能提供强大的数据访问方法以支持各种工作负载方面表现出色。然而,它们的实现方式存在显著差异,反映了各自独特的设计理念和使用场景。 在这篇文章中将介绍PostgreSQL提供的各种数据访问方法,其中包括一个非常独特的特点:PostgreSQL不支持聚集索引。这一根本性的差异对于理解PostgreSQL与SQL Server在数据存储和检索上的不同方式至关重要。

顺序扫描

任何数据库系统的核心都离不开最简单的数据访问方法,就是扫描表中的所有行。 PostgreSQL 通过顺序扫描(Sequential Scan)来实现这一点,它逐行读取表中的每一行。 虽然对于大型数据集而言,这看起来可能效率不高,但在特定场景下,它往往是最实际的选择。 当处理小型表时,使用索引的开销通常超过其带来的好处,因此顺序扫描非常有效。 此外,当查询需要表中大量行时,例如需要查询超过50%的数据行时候,顺序扫描可以通过最小化随机I/O来优于索引扫描。 SQL Server采用了一种类似的技术,称为表扫描(Table Scan),它逐行读取整个表。无论是PostgreSQL还是SQL Server都依赖其查询优化器来决定何时应选择表扫描而不是使用索引扫描。例如,在没有合适索引的情况下,或者查询涉及广泛的过滤条件时,优化器将选择全表扫描。尽管顺序扫描和表扫描有时被批评为较慢,但它们依然是数据库处理特定工作负载时必不可少的工具。

在PostgreSQL中,所有的表默认存储在堆结构(Heap)中,这意味着行没有固定的顺序。PostgreSQL中没有聚集索引的概念,这意味着顺序扫描通常会访问以任意顺序存储的行。

索引扫描

在PostgreSQL中,索引扫描(Index Scan)是一个基本的查询执行方法,它使用索引来高效地检索符合特定查询条件的行。 当执行索引扫描时,PostgreSQL会遍历索引结构(B树)来查找满足查询条件的行的位置(元组指针)。这些指针将引导PostgreSQL定位到堆表中的相应行,进而检索完整的行数据。 在PostgreSQL中,索引扫描的关键之处在于,它对堆表的查找操作是作为索引扫描的一部分内部执行的。因此,PostgreSQL 执行计划将索引扫描显示为一个单独的操作,它封装了索引遍历和随后从堆表中检索行数据这两个步骤。

与此不同,SQL Server的执行计划明确区分了这两个步骤。在SQL Server中,索引查找(Index Seek)操作负责遍历索引以找到匹配的行。当索引不包含查询所需的所有列时,SQL Server会引入一个单独的操作,对于聚集索引表是键查找(Key Lookup),对于堆表则是RID查找(RID Lookup)。这些查找操作会直接从基础表中获取额外的列。通过分离这些步骤,SQL Server的执行计划提供了一个更加清晰详细的视图,展示查询如何访问数据,包括索引遍历和数据行检索的成本和行为。 这种执行计划表示的差异凸显了不同的设计理念。 PostgreSQL将堆查找集成到索引扫描操作中,呈现一个简化的执行计划。然而,这也可能掩盖索引扫描中堆访问部分的具体成本。另一方面,SQL Server明确分离提供了对查询执行过程更为详细的洞察。例如,当SQL Server的执行计划中包含键查找时,立刻可以看出索引缺少一些必需的列,这可以帮助数据库管理员通过创建覆盖索引来消除查找操作。这种透明度对于识别和解决复杂查询中的性能瓶颈特别有帮助。

位图索引扫描与位图堆扫描

对于具有多个条件或过滤器的查询,PostgreSQL经常使用位图堆扫描(Bitmap Heap Scan),这是一种将索引访问的精确性与批量读取的高效性相结合的混合方法。 在执行此类查询时,PostgreSQL首先使用相关的索引构建一个位图,即匹配查询条件的行的压缩表示。与逐行访问不同,位图使PostgreSQL能够批量获取这些行从而减少随机磁盘 I/O。这种方法对于必须同时评估多个条件的大型表特别有用,例如按客户年龄和地点进行过滤。位图扫描Bitmap Scan也分为两个阶段,第一个阶段是Bitmap Index Scan,第二个阶段是Bitmap Heap Scan。Bitmap Heap Scan采用Bitmap Index Scan生成的bitmap(或者经过 BitmapAnd 和 BitmapOr 节点通过一系列位图集操作后,生成的bitmap)来查找相关数据。位图的每个page可以是精确的(直接指向tuple的)或有损的(指向包含至少一行与查询匹配的page)。

SQL Server并没有直接等同于位图堆扫描的操作,但它在并行查询执行计划中使用位图过滤(Bitmap Filtering)。位图堆扫描在处理需要多个索引扫描的查询时尤其具有优势,因为它将这些操作合并为一个更高效的过程。这种方法突显了 PostgreSQL 在动态优化复杂查询方面的独特能力。通过平衡顺序访问和索引访问的优点,位图堆扫描架起了精确性与高效性之间的桥梁,使其在分析和报告工作负载中变得不可或缺。

仅索引扫描

在PostgreSQL中,仅索引扫描(Index-Only Scans)是一种查询执行特性,允许数据完全从索引中检索,跳过对堆表的访问。 当查询只涉及索引中的列时,这种方法是可行的。在进行仅索引扫描时,PostgreSQL直接从索引的叶节点中获取数据,从而显著减少了I/O操作并提高了查询性能,特别适用于读密集型工作负载。例如,如果一个查询仅检索客户的姓名和电子邮件,并且这些列是索引的一部分,那么数据库完全避免了访问堆表的开销。在SQL Server中,类似的概念是通过覆盖索引(Covering Indexes)来实现的,在索引定义中包含了额外的列(超出索引键列的部分)。这些额外的列被称为包含列(Included Columns),它们允许 SQL Server 直接从索引中检索所有所需的数据,而无需执行键查找(Key Lookup)或 RID 查找(RID Lookup)。

并行查询执行

随着数据集的增大和查询变得更加复杂,采用并行处理对于保持性能至关重要。 PostgreSQL支持并行查询执行,允许多个工作进程分担和处理大规模的工作负载。例如,并行扫描将一个大型表分成多个分段,每个工作进程同时扫描其中的一部分。这种方法能够显著减少资源密集型操作的查询时间。SQL Server也支持执行计划中的并行处理,使用并行扫描(Parallel Scan)和合并流(Gather Streams)等操作符,将工作负载分配并合并到多个工作线程中。SQL Server的并行查询引擎与其优化器紧密集成,通常能为事务型OLTP和分析型OLAP工作负载生成高效的执行计划。

聚集索引的作用

PostgreSQL和SQL Server之间最显著的区别之一是PostgreSQL不支持聚集索引。 在SQL Server中,聚集索引定义了表中行的物理顺序。这可以显著提高范围查询或返回按排序顺序排列行的查询的性能,因为数据已经根据索引键物理排序。 在PostgreSQL中,所有表都以堆(heap)形式存储,这意味着行没有特定的存储顺序。虽然PostgreSQL提供了一个名为CLUSTER的命令,可以基于索引物理重新排序表,但这个操作不是动态的,必须手动执行。此外,CLUSTER创建的排序不会随着行的插入、更新或删除而保持。 PostgreSQL的这种设计选择优先考虑灵活性,而不是聚集索引可能带来的性能提升。 通过保持表的无序,PostgreSQL 允许多个索引并存,这对于大量数据写入的场景或者说写多读少的场景非常有利。

总结

PostgreSQL 和 SQL Server 中的数据访问方法展示了各自系统的优势和优先事项。PostgreSQL 的灵活性,例如位图堆扫描、仅索引扫描,使其成为开发者在查询执行上寻求精确控制的强大选择。 然而,PostgreSQL 不支持聚集索引是其与 SQL Server 的一个关键区别。另一方面,SQL Server 使用聚集索引来提供表行的物理排序,这可以显著有利于范围查询和排序操作。 这种结构性差异体现了两个系统的不同哲学:PostgreSQL 倾向于适应性,而 SQL Server 强调紧密集成的优化。理解这些差异能够帮助数据库专业人员做出明智的决策,并针对每个平台的独特优势优化查询。

本文版权归作者所有,未经作者同意不得转载。

为何PostgreSQL没有聚集索引?解读两大数据库的设计差异的更多相关文章

  1. navicat------------利用navicat查看两个数据库之间的差异

  2. mysql----------利用navicat查看两个数据库之间的差异

  3. Key Lookup开销过大导致聚集索引扫描

    以前总结过一篇文章SQL SERVER中什么情况会导致索引查找变成索引扫描 介绍了几种索引查找(Index Seek)变成索引扫描(Index Scan)的情形.昨天写一篇文章的时候,也遇到了一个让人 ...

  4. SQL索引学习-聚集索引

    这篇接着我们的索引学习系列,这次主要来分享一些有关聚集索引的问题.上一篇SQL索引学习-索引结构主要是从一些基础概念上给大家分享了我的理解,没有实例,有朋友就提到了聚集索引的问题,这里列出来一下: 其 ...

  5. SQL Server索引进阶:第三级,聚集索引

    原文地址: Stairway to SQL Server Indexes: Level 3, Clustered Indexes 本文是SQL Server索引进阶系列(Stairway to SQL ...

  6. SQLServer中重建聚集索引之后会影响到非聚集索引的索引碎片吗

    本文出处:http://www.cnblogs.com/wy123/p/7650215.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...

  7. mysql聚集索引

    转自http://www.cnblogs.com/tuyile006/archive/2009/08/28/1555615.html 微软的SQL SERVER提供了两种索引:聚集索引(cluster ...

  8. SQL Server - 索引详细教程 (聚集索引,非聚集索引)

    转载自:https://www.cnblogs.com/hyd1213126/p/5828937.html 作者:爱不绝迹 (一)必读:深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录. ...

  9. SQL Server的聚集索引和非聚集索引

    微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonclustered index,也称非聚类索引.非簇集索引)…… (一) ...

  10. SQL存储原理及聚集索引、非聚集索引、唯一索引、主键约束的关系(补)

    索引类型 1.          唯一索引:唯一索引不允许两行具有相同的索引值 2.          主键索引:为表定义一个主键将自动创建主键索引,主键索引是唯一索引的特殊类型.主键索引要求主键中的 ...

随机推荐

  1. 开源一款DDS信号发生扩展板-FreakStudio多米诺系列

    原文链接: FreakStudio的博客 摘要 信号发生扩展板通过SPI接口生成可调频率和幅度的正弦波.方波和三角波,频率小于1MHz.支持幅度调节,提供原始和6倍放大输出接口.配备5阶低通滤波器.噪 ...

  2. 2024.11.19随笔&联考总结

    联考 看到 T1 就知道一定是简单计数题然后发现 \(O(n)\) 可以过于是就大概写了写式子就开写.写的过程中犯了一些低级错误,代码重构了一次才过.耽误的时间比较久.然后开 T2,一眼有一个 \(O ...

  3. PowerShell开发小工具 · 四张照片拼成一张

    小工具的设计与实现------选四张照片拼成一张照片. 很经典的应用情景,市面上有很多类似的小软件,特别是手机应用.为了方便学习巩固PowerShell,今天笔者使用它来实现. [设计思路] 选择四张 ...

  4. C#枚举帮助EnumHelper

    1 public class EnumHelper 2 { 3 #region 获取枚举 4 public static List<EnumValue> GetEnumList(Type ...

  5. WSL2 - Ubuntu 22.04使用记录

    1 安装 搭配Windows Terminal使用为佳,在微软商店可下载: 然后依照官网描述即可. 命令行中运行wsl --install即可.不过由于想自行指定发行版,于是: wsl --list ...

  6. 【面试题】实现 queryParse 函数,完成解析 URL 参数的功能

    问题:实现 queryParse 函数,完成解析 URL 参数的功能 /** * 问题:实现 queryParse 函数,完成解析 URL 参数的功能 * * 用法: * ```js * const ...

  7. [Vue warn]: Unknown custom element: did you register the component correctly?

    前言 [Vue warn]: Unknown custom element: did you register the component correctly? For recursive compo ...

  8. docker 版本号说明

    17.03 版本以前 Docker CE 在 17.03 版本之前叫 Docker Engine, 版本说明参考这里 => Docker Engine release notes, 可以看到 D ...

  9. Python 潮流周刊#94:如何解决 FastAPI 的大文件传输问题?(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  10. 【Java】网络编程

    InternetAccess类的使用 一.概述 计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大.功能强的网络系统,从而使众多的计算机可以方便地互相传递信息共享硬件 ...