本文档围绕数据库存储与索引展开,核心涵盖数据文件与索引文件基础、索引分类与数据结构、索引操作 SQL、表连接机制及索引选择策略,同时涉及空间存储相关预备知识。
一、数据文件与索引文件基础
1. 数据文件类型
- 堆文件(Heap file):无排序规则,记录随机存储。
- 顺序文件(Sequential file):按特定属性(称为键)排序存储。
2. 索引文件核心特性
- 独立于数据文件的附加文件,用于快速定位数据记录。
- 存储(键,值)对:键为属性值(如学号、姓名),值为指向对应记录的指针。
- 单个表可建立多个索引,适配不同查询场景。
3. 关键键类型
- 主键(Primary key):唯一标识元组,DBMS 通常自动为单属性主键创建索引,一个表最多一个主键索引。
- 顺序文件键:数据文件的排序依据(若有排序)。
- 索引键:索引自身的组织依据。
二、索引分类:聚集索引与非聚集索引
1. 核心区别
- 聚集索引(Clustered):索引中相邻的记录在数据文件中物理位置也相邻。
- 实现方式:数据文件按索引键排序存储;或数据直接存储在索引中(无独立数据文件)。
- 优势:极大优化范围查询性能。
- 非聚集索引(Unclustered):索引中相邻的记录在数据文件中可能物理分散。
2. 使用限制
- 每个表仅能有一个聚集索引,但可有多个非聚集索引。
三、索引数据结构
1. 主流数据结构
- B + 树:最常用,非二叉搜索树,具有高扇出特性。
- 哈希表:适用于精确匹配查询。
- 专用索引:位图索引、R 树、倒排索引等。
2. B + 树详细特性
(1)核心设计思想
- 节点与物理页对应,保证 I/O 效率。
- 树结构平衡,高度可控,查询、插入、删除效率稳定。
- 叶子节点构成链表,支持高效范围查询。
(2)节点规则
- 非叶子节点:键数量在 d, 2d 之间(d 为度数),n 个键对应 n+1 个指针,指向子节点。
- 叶子节点:键数量在 d, 2d 之间,存储指向数据记录的指针,同时包含指向下一叶子节点的指针。
(3)操作逻辑
- 精确查询:从根节点出发,逐层定位至叶子节点,找到对应数据指针。
- 范围查询:定位到范围起始键对应的叶子节点后,通过链表遍历后续符合条件的节点。
- 插入操作:在叶子节点插入,溢出时分裂节点并将中间键向上递归传递,维持树平衡。
3. 哈希表核心特性
(1)基本原理
- 通过哈希函数 h (key) 将键映射为桶编号(slot-id),实现键到地址的直接转换。
- 每个哈希桶对应一个物理页,存储多条记录。
(2)关键组件
- 哈希函数:常用除法哈希(h (x)=(a*x+b)% M)、乘法哈希,目标是让键均匀分布。
- 哈希表大小 M:需选择质数,利用率通常约 90%,按数据量和每页记录数计算(例:50000 条记录,每页 10 条,M 约为 5555)。
- 冲突解决:开放寻址(如线性探测)、再哈希、分离链接(溢出页链表)。
4. B + 树与哈希表对比
| 特性 | B + 树 | 哈希表 |
|---|---|---|
| 适用查询类型 | 精确查询、范围查询、邻近查询、顺序扫描 | 仅精确查询 |
| 时间复杂度 | 稳定 O (logN)(查询、插入、删除) | 平均 O (1)(查询),存在冲突开销 |
| 动态调整 | 支持平滑扩容 / 缩容 | 扩容需重新哈希,成本较高 |
| 核心优势 | 排序特性适配多场景查询 | 精确查询效率极高 |
四、索引操作 SQL 语法
1. 创建索引
- 基本语法:
CREATE [UNIQUE] [CLUSTERED] INDEX <索引名> ON <表名>(<列名>[<次序>][,<列名>[<次序>]]...); - 关键参数:UNIQUE(索引值唯一对应数据记录)、CLUSTERED(创建聚集索引)、次序(ASC 升序,默认;DESC 降序)。
- 示例:
- 学生表按学号升序建唯一索引:
CREATE UNIQUE INDEX Stusno ON S (Sno ASC); - 选课表按学号升序、课程号降序建唯一索引:
CREATE UNIQUE INDEX SCno ON SC(Sno ASC, Cno DESC);
- 学生表按学号升序建唯一索引:
2. 删除索引
- 语法:
DROP INDEX <索引名>; - 效果:从数据字典中删除该索引的描述信息。
- 示例:
DROP INDEX Stusno;(删除学生表的 Stusno 索引)
3. PostgreSQL 索引特性
- 默认使用 B 树存储索引(如
CREATE INDEX ir ON public.r USING btree (a);)。 - 可通过
EXPLAIN查看查询规划,EXPLAIN ANALYZE查看规划 + 实际执行时间。
五、表连接机制
1. 三种核心连接算法
(1)嵌套循环连接(Nested-Loop Join)
- 逻辑:外层循环遍历一张表(驱动表,通常为小表),内层循环按连接键在另一张表(内表,需有索引)中匹配。
- 适用场景:连接数据子集小,且内表连接字段有索引。
- 复杂度:O (N²),若驱动表极小可接近 O (N)。
(2)合并连接(Merge Join)
- 逻辑:先将两张表按连接键排序,再对排序后的结果进行合并匹配。
- 适用场景:表已排序或适合全表扫描,支持等值和非等值连接(不含!=)。
- 复杂度:O (NlogN)(排序开销),若表已排序则为 O (N)。
(3)哈希连接(Hash Join)
- 逻辑:用较小表的连接键构建内存哈希表,再扫描较大表并探测哈希表匹配。
- 适用场景:大数据集等值连接,无索引或索引条件模糊。
- 复杂度:O (N),需足够内存存储哈希表,大表可分区写入临时段。
2. 连接算法对比
| 类别 | 使用条件 | 依赖资源 | 核心优势 | 缺点 |
|---|---|---|---|---|
| 嵌套循环连接 | 任何条件 | CPU、磁盘 I/O | 高选择性索引或限制性搜索时效率高,快速返回首结果 | 索引丢失或查询限制不足时效率低,大表表现差 |
| 哈希连接 | 等值连接(=) | 内存、临时空间 | 无索引时优于嵌套循环,大数据集效率高 | 需大量内存建哈希表,首结果返回慢 |
| 合并连接 | 等值 / 非等值连接(>、<、>=、<=) | 内存、临时空间 | 非等值连接时优于哈希表,已排序表无需额外排序 | 无索引时需排序,开销较高 |
六、索引选择策略
1. 索引使用场景
DBMS 会在以下情况使用索引:
- 查询条件(WHERE/ON 子句)中对属性 K 进行精确匹配。
- 对属性 K 使用范围谓词(如 K>5、20<=K<=30)。
- 表连接时以 K 为连接键。
2. 索引选择核心准则
- 按查询优先级排序,优先为高频、重要查询优化。
- 仅为查询涉及的表建立索引,避免无用索引开销。
- 优先选择能加速多个查询的属性作为索引键。
- 多属性索引:若查询条件包含多个属性匹配,或 SELECT 子句仅需这些属性(构成覆盖索引),可建立多属性索引。
3. 覆盖索引特性
- 索引包含查询所需全部数据,无需访问数据文件即可完成查询。
- 示例:索引 R (K1,K2) 可直接回答查询
SELECT K2 FROM R WHERE K1=55。
4. 索引失效情况
- 索引键无查询条件匹配,或查询条件过于模糊。
- 全表扫描成本低于索引查询(如小表、高比例数据返回)。
七、空间存储与索引预备知识
1. 空间填充曲线
- 作用:重用关系数据库物理模型,将空间数据映射为一维数据。
- 类型:Z 曲线(Z-Curve)、希尔伯特曲线(Hilbert Curve)。
- 应用:用于空间数据的有序存储与快速检索。
2. 空间索引
- 定位:作为新的空间技术,区别于传统数值索引。
- 相关工具:PostGIS(PostgreSQL 的空间扩展模块)。
- 参考资料:《Spatial Databases: A Tour》第 4 章、《空间数据库管理系统概论》第 6 章。
八、核心概念总结
- 基础区分:数据文件 vs 索引文件、主键 vs 索引键、聚集索引 vs 非聚集索引。
- 核心工具:B + 树(主流索引结构)、SQL 索引操作、三种表连接算法。
- 核心逻辑:索引适配查询场景(精确匹配、范围查询、表连接),需结合数据量、查询类型选择索引属性。
九、索引选择决策表
该表基于文档中索引核心特性、查询场景及数据特征,梳理不同条件下的最优索引方案,助力快速匹配索引设计需求。
| 决策维度 | 具体条件 | 推荐索引类型 / 方案 | 不推荐方案 | 核心依据(对应文档知识点) |
|---|---|---|---|---|
| 查询类型 | 1. 精确匹配查询(如 "WHERE Sno=20") | - 单属性 B + 树索引- 哈希表(数据量大且无范围查询需求时) | 多属性索引(仅用单个属性匹配时) | 1. 哈希表适合精确查询,平均 O (1) 时间;2. B + 树支持精确查询且兼容后续扩展需求 |
| 2. 范围查询(如 "WHERE Grade>=85""20<=Age<=30") | 单属性 / 多属性聚集 B + 树索引 | 哈希表(无法支持范围遍历) | 1. 聚集索引中相邻记录物理位置相邻,极大优化范围查询性能;2. B + 树叶子节点链表支持范围遍历4 | |
| 3. 表连接查询(如 "S.Sno=SC.Sno") | 连接键(如 Sno)的 B + 树索引(聚集 / 非聚集均可,优先聚集) | 无索引(嵌套循环连接会退化至 O (N²)) | 1. 索引可减少连接时的表扫描次数7;2. 嵌套循环 / 合并连接依赖索引提升效率 | |
| 4. 多条件查询(如 "WHERE Sdept='EE' AND Sage=20") | - 多属性联合 B + 树索引(按查询条件优先级排序,如 (Sdept,Sage))- 覆盖索引(若 SELECT 仅需 Sno,Sname) | 多个独立单属性索引(需多次索引查找) | 1. 多属性索引可一次性匹配多个条件;2. 覆盖索引无需访问数据文件,直接返回结果9 | |
| 数据特征 | 1. 数据量小(如 <1 万条记录,如 "班级学生表") | 无需建索引(全表扫描成本低于索引查询) | 复杂多属性索引 | 小表全表扫描 I/O 开销低,索引维护成本高于查询收益8 |
| 2. 数据量大(如 > 10 万条记录,如 "全校选课表 SC") | - 聚集 B + 树索引(按高频查询键排序,如 SC.Sno)- 分区索引(若数据按时间 / 类别分区) | 哈希表(不支持范围查询,扩展性差) | 1. 大表需通过聚集索引减少范围查询的物理 I/O2;2. B + 树支持平滑扩容,适配数据增长5 | |
| 3. 数据更新频繁(如 "实时订单表",频繁 INSERT/DELETE) | 非聚集 B + 树索引(避免聚集索引更新导致的物理数据移动) | 聚集索引(更新会引发大量数据重排) | 聚集索引中数据物理顺序与索引一致,更新时需调整物理位置,开销高 | |
| 4. 数据静态 / 更新少(如 "历史成绩表") | 聚集 B + 树索引(最大化查询效率,无需频繁维护) | 哈希表(无法利用数据静态特性优化) | 静态数据适合通过聚集索引固化物理顺序,长期提升查询性能3 | |
| 表结构与约束 | 1. 表有主键(如 Student.Sno,唯一标识元组) | DBMS 自动创建的单属性主键 B + 树索引(无需额外创建) | 重复创建主键索引 | DBMS 会自动为单属性主键创建索引,重复创建浪费资源1 |
| 2. 表无主键,但有唯一约束(如 "教师工号表,工号唯一") | 唯一 B + 树索引(确保约束同时支持查询) | 非唯一索引(无法保证数据唯一性) | 唯一索引可同时满足 "数据约束" 与 "查询加速" 需求,对应 CREATE UNIQUE INDEX 语法6 | |
| 3. 多表关联频繁(如 Student、SC、Course 三表连接) | - 各表连接键的 B + 树索引(如 Student.Sno、SC.Sno、SC.Cno、Course.Cno)- 多表联合覆盖索引(如 SC (Sno,Cno,Grade)) | 仅单表索引(多表连接时仍需大量扫描) | 连接键索引减少多表关联时的匹配开销7;覆盖索引可直接返回多表查询结果,无需跨表访问9 | |
| 特殊场景 | 1. 空间数据查询(如 "查询某区域内的 POI") | 空间索引(如 R 树)+ 空间填充曲线(Z 曲线 / Hilbert 曲线) | 传统数值索引(无法处理空间维度关系) | 空间索引专门适配空间数据,空间填充曲线将空间数据映射为一维,重用关系数据库物理模型 |
| 2. 统计分析查询(如 "COUNT (*) WHERE Cdept='CS'") | 覆盖索引(包含查询所需统计字段,如 (Cdept)) | 非覆盖索引(需回表查询,增加开销) | 覆盖索引可直接通过索引完成统计计算,无需访问数据文件9 |