PostgreSQL 为什么不选择 B+ 树索引? - Lafite

news/2025/10/16 19:03:03/文章来源:https://www.cnblogs.com/hefeng2014/p/19146407

我们知道,MySQL 的索引设计使用了 B+Tree,而 PostgreSQL 使用了 B-Tree,
那 PostgreSQL 为什么不使用 B+Tree 做索引结构呢?今天就来聊一聊这个话题。

B+Tree 和 B-Tree

B+TreeB+Tree

主键索引的叶子节点存储数据,非叶子节点(索引节点)则存储 key 和指针。这样存储的优势是可以在索引节点通过二分查找快速找到数据所在页,时间复杂度为 O(logmN),其中 N 是总的节点数量,m 是每个节点的子节点个数。找到数据页后再去数据页中找数据就很容易了。

image

B+Tree的第二个特点是叶子节点用双向链表串联起来,这样范围查询优势很大,时间复杂度为O(logmN+K)。

B-Tree跟

B+Tree不一样的是,B-tree所有节点都可以存储数据,包括根节点,内部节点,叶子节点。

image

随机查询:因为 B-Tree在非叶子节点也能存储数据,B-Tree可能在非叶子节点提前终止查询,查询路径更短。

范围查询:B-Tree查询一个数据范围时需要中序遍历多个层级,这一点效率不如 B+Tree。

PostgreSQL 索引

索引介绍

PostgreSQL 索引对 B-Tree 进行了改造。改造后的索引结构如下图:

image

上图的索引结构中最顶层是元数据页,存储索引根节点页相关信息。内部节点位于根节点下面,只包含键值和指向子页面的指针。叶子页位于最下面一层,存储所有指向实际表数据行(TIDs)的指针。

什么是 TID?PostgreSQL 采用堆表存储,数据独立于索引存储在一个无序的结构中。数据行插入时,数据库会找到一个空闲的空间来存放它,并记录一个唯一的物理地址,称为 TID,由页号和行指针组成。

因为 B-Tree的叶子节点只保存 TIDs,不保存真实数据,因此每个数据页能保存更多的叶子节点。跟 B+Tree相比,在相同数据量下,B-Tree高度更低。

PostgreSQL 索引中无论是内部节点还是叶子节点,数据都以递增顺序存储,同一层的数据页由双向链表连接。因此通过遍历链表就可以获取一个有序的数据集,范围查询并不需要中序遍历。

PostgreSQL 索引页格式如下,(下图来自官网):

image

下表对每个属性进行解释:

Item Description
PageHeaderData 24 bytes long. Contains general information about the page, including free space pointers.
ItemIdData Array of item identifiers pointing to the actual items. Each entry is an (offset,length) pair. 4 bytes per item.
Free space The unallocated space. New item identifiers are allocated from the start of this area, new items from the end.
Items The actual items themselves.
Special space Index access method specific data. Different methods store different data. Empty in ordinary tables.

三个优化

Deduplication

在索引中,如果存在大量相同的键值(比如一个被频繁更新的状态标志),PostgreSQL 会将这些重复的键值合并存储,只保留一个键值和多个对应的 TID 列表,这大大节省了空间,提高了缓存效率。

Index Only Scan

虽然叶子节点不保存完整数据,但叶子节点中除了存储键值和 TID,也可以保存查询中需要的某几个字段值(非索引列值),类似于覆盖索引。

这样,对于只查询索引列和包含列的语句,可以不用通过 TID 去堆上查找数据,直接通过索引就获取到查询结果。

反向键索引

PostgreSQL 可以创建反向排序的索引,这对于缓解插入热点(如递增主键、时间等字段)问题非常有效。创建索引的时候需要指定反向索引,例如下面 SQL 给员工编号(emp_id)创建一个反向键索引:

CREATE INDEX idx_emp_id ON tb_emploee(emp_id REVERSE);
总结

PostgreSQL 的索引结构虽然叫 B-Tree,但其实它实现了 B+Tree的功能,并且在索引上做了一些优化,使索引效率更高。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/938442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Joeys shell

您熟悉bash的语法吗?"Youre afraid of bugs? Get a bug!" --Joey Tribbiani, "FRIENDS". 想找个mini shell来看看源码,浏览了些网页,有“这玩意也配叫shell?”之感。bash-1.14.7.tar.gz 1996…

Redis 集群从部署到可视化管理全流程(超详细实战指南)

一、为什么需要 Redis 集群? Redis 单机模式存在三大瓶颈: 容量瓶颈:单机内存有限,无法存储海量数据; 并发瓶颈:单线程处理能力有限,高并发下性能易打满; 高可用瓶颈:单机故障会导致服务中断,无自动容灾能力…

什么是BPM流程自动化?从“财务报销”入手,一文读懂企业效率引擎

在企业的日常运营中,我们总能听到“数字化转型”、“降本增效”这样的热词。但它们究竟意味着什么?对于终日忙于具体事务的部门负责人和一线员工而言,这些宏大的概念,有时远不及一张迟迟未能签批的报销单来得真切。…

软件工程学习日志2025.10.16

📚 今日学习主题 NoSQL数据库基础与MongoDB实际操作 💡 核心知识点总结NoSQL数据库特点• 灵活的可扩展性:轻松应对数据量增长 • 灵活的数据模型:不受固定表结构限制 • 与云计算紧密融合:适合分布式环境部署 …

P1072 [NOIP 2009 提高组] Hankson 的趣味题

P1072 [NOIP 2009 提高组] Hankson 的趣味题题目传送门 欢迎光顾我的博客 (下面称 \(V\) 为 \(a_0,a_1,b_0,b_1\) 的值域) 我们在小学二年级就学过,对于两个正整数 \(a,b\) ,可以分别将它们表示为 \(mx,my\) ,其中…

Apifox 9 月更新| AI 生成接口测试用例、在线文档调试能力全面升级、内置更多 HTTP 状态码、支持将目录转换为模块 - 实践

Apifox 9 月更新| AI 生成接口测试用例、在线文档调试能力全面升级、内置更多 HTTP 状态码、支持将目录转换为模块 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !impo…

Pasos和RAFT算法

Pasos和RAFT算法Paxos 提出时间1990年,RAFT提出时间2013年。RAFT 是Paxos的简化版,或者说是提高投票效率,但是降低了投票公平性的妥协方案。 RAFT 分布式raft(Replicated And Fault Tolerant)选举算法原理分成三个角…

25w41a快照测评:鹦鹉螺成精了?长矛教你戳穿末影人!

25w41a快照测评:鹦鹉螺成精了?长矛教你戳穿末影人! 🚨 快照速递:1.21.11 第一个测试版来啦! 家人们谁懂啊!Mojang 突然扔出 25w41a 快照,本以为是修 bug 的小更新,结果直接塞了一堆新玩具 —— 鹦鹉螺能穿装…

Day15-C:\Users\Lenovo\Desktop\note\code\JavaSE\Basic\src\com\classlei

Object类 clone() 用于创建对象的副本,是实现对象复制的重要方式 @Override public clonetest clone() {// 注意返回类型是clonetest而非Objecttry {// 调用Object类的clone()方法,正常情况下clone()方法返回object类…

window电脑开启hyperV虚拟化功能后导致本地服务端口被占用问题处理方案

window电脑开启hyperV虚拟化功能后,会预留一些动态端口,导致本地服务端口被占用。 而且使用端口查找命令还找不到这个端口的进程。 处理方案:重新设置预留端口。 1、使用命令netsh int ipv4 show dynamicport tcp可…

RAG检索质量差?这5种分块策略帮你解决70%的问题

RAG 的关键其实就在检索这一步:检索质量好不好,很大程度上取决于怎么切分和存储文档——也就是分块(Chunking)这个看起来不起眼的环节。 固定分块、递归分块、语义分块、结构化分块、延迟分块,每种方法在优化上下…

初识pytorch:网络骨架中的填充之各种层

目录层:网络骨架中的各种填充物核心计算层全连接层卷积层循环层Transformer层激活函数层(引入非线性)正则化层(防止过拟合)Dropout层(nn.Dropout / nn.Dropout2d)批归一化层(nn.BatchNorm2d / nn.BatchNorm1d)…

Day5字符型

#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> #include<time.h>int main(){//字符型变量char ch = a;char ar = z;//相同的符号有不同的含义char c = 0;…

本地链路地址

本地链路地址 (Link-Local Address)协议族:在 IPv4 和 IPv6 中都存在,但更常见于IPv6问题中。地址范围:IPv4:169.254.0.0/16IPv6:fe80::/10作用范围:局限于单个物理网络链路(或广播域),也就是你直接连接的交换…

Meta推出Agent Learning via Early Experience,推动语言代理自主学习新范式

原文: https://mp.weixin.qq.com/s/fhNRtk0FhK6K9_LBLwbDSg 全文摘要在人工智能领域,语言代理(Language Agents)的自主学习能力一直是研究热点。传统依赖专家数据的模仿学习(Imitation Learning)存在泛化能力弱、…

fiddlerscriptCustomize Menus - 特洛伊

Customize Menus To customize menus in Fiddler, add rules using FiddlerScript with Global scope. For example: Add context-menu item to open currently selected URLs using Firefoxpublic static ContextActi…

Fiddler And LINQ - 特洛伊

Since moving to Google at the beginning of 2016, I’ve gained some perspective about my work on Fiddler over the prior 12+ years. Mostly, I’m happy about what I accomplished, although I’m a bit awed …

计算机视觉在自动化质检中的应用

本文探讨了如何利用计算机视觉技术实现自动化质量检测,通过定制化视觉模型识别制造过程中的缺陷,涵盖边缘计算在工业场景的应用及机器学习服务如何帮助提升运营效率。计算机视觉在自动化质检中的应用 在2022年6月举行…

深入解析:从 Vercel 构建失败谈 Git 大小写敏感性问题:一个容易被忽视的跨平台陷阱

深入解析:从 Vercel 构建失败谈 Git 大小写敏感性问题:一个容易被忽视的跨平台陷阱pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…