数据库之索引的底层数据逻辑及应用

数据库索引原理与设计:B+树、哈希索引与优化策略,

索引(index)是帮助数据库高效获取数据的数据结构。

索引的数据结构

堆存储
一个数据表
使用二叉树存储
使用二叉树存储的
极端情况下的单链形式
极端情况下的单链形式
大数据量下,层级越深,查询效率越低。

平衡二叉树
平衡二叉树

多路平衡查找树
多路平衡查找树
B+树的结构
B+树
所有的数据都存储在叶结点中
叶结点间以单向链表链接

数据库中的B+树结构
数据库中的B+树
叶结点间以双向链表链接

为什么是B+树?

  1. 一个结点存储在一个页上,一页的大小是8K(SQL Server),页不可拆分。B+树中不存放数据,则在一页中可以存放的Key个数更多,使得树的层级减少,查找效率增加;
  2. 搜索效率稳定;
  3. 叶子节点间的双向链表便于排序。

优缺点

索引:帮助高效获取数据的数据结构。
优:

  1. 高效获取数据,减少IO成本。
  2. 通过索引对数据进行排序,降低CPU消耗

缺:

  1. 占用空间
  2. 降低了更新表的效率(insert、update、delete)

哈希索引

哈希索引的数据结构
通过内存中的哈希表来访问数据。
哈希索引的内存用量固定不变,是存储桶数量的函数。
只能进行等值匹配(=,in),不能进行范围查询(between,<,>);
无法利用索引进行排序(哈希值是无序的);
查询效率高,通常只需要一次检索(没有哈希冲突的情况)(效率>B树)

索引分类

物理结构

类型物理存储特点
聚集索引叶节点包含基础表的数据页可以没有但必须唯一
非聚集索引包含索引键值和指向表数据存储位置的行定位器可以有多个

聚集索引

聚集索引的物理存储

聚集索引特殊的方面是:聚集索引的叶级是实际的数据。

表上如果没有建立聚集索引,则是按照堆(HEAP)存放的。
在建立聚集索引时,会开创新的物理空间,将数据重新排序,按照和聚集索引排序条件声明的相同物理顺序存储。但原有的堆表并不会被释放, 旧的结构只有在提交索引创建事务后才会释放。

这意味着,一旦到达索引的叶级,就到达了数据

聚集索引的选取规则:

如果有主键,默认主键索引就是聚集索引;

如果没有主键,数据库引擎会自动向行添加一个唯一标识符RID,使每个键唯一。RID不可被用户查看及访问;

如果对具有多个现有非聚集索引的堆创建聚集索引,则必须重新生成所有非聚集索引,以使它们包含聚集键值而非行标识符 (RID);

在聚集索引中,叶节点包含基础表的数据页;

数据链内的页和行将按聚集索引键值进行排序。 所有插入操作都在所插入行中的键值与现有行中的排序顺序相匹配时执行。

非聚集索引

非聚集索引是为提高聚集索引未涵盖的常用查询的性能。

非聚集索引并不改变其所在表的物理结构,而是额外生成一个聚集索引的B树结构,但叶子节点是对于其所在表的引用,这个引用分为两种,如果其所在表上没有聚集索引,则引用行号。如果其所在表上已经有了聚集索引,则引用聚集索引的页。

非聚集索引,到达了叶级只是找到了数据的引用

非聚集索引的回表查询

索引关键字

类型关键字含义特点
主键索引PRIMARY针对主键建立的索引默认自动创建、唯一
唯一索引UNIQUE避免字段值的重复不唯一
全文索引FULLTEXT查找文本中的关键字不唯一
常规索引实现快速查找不唯一

主键索引:
关键字:primary
针对主键创建的索引,默认自动创建,只能有一个

唯一索引:
关键字:unique
避免表中某列的值重复,确保索引键不包含重复的值,因此,表或视图中的每一行在某种程度上是唯一的。唯一性可以是聚集索引和非聚集索引的属性。
但唯一索引可以有多个

常规索引:快速定位特定数据

全文索引:
关键字:fulltext
查找的是文本中的关键字,而非比较索引中的值

索引语法

CREATE UNIQUE INDEX index_name ON table_name (column_name) ;---非空索引
CREATE PRIMARY KEY INDEX index_name ON table_name (column_name) ;---主键索引

使用ALTER TABLE语句创建索引

alter table table_name add index index_name (column_list) ;
alter table table_name add unique (column_list) ;
alter table table_name add primary key (column_list) ;

查看索引

exec sp_helpindex table_name;

删除索引

drop index index_name on table_name ;
alter table table_name drop index index_name ;
alter table table_name drop primary key ;

验证索引:
在未使用索引之前,执行SQL语句,查看SQL耗时

SELECT * FROM table_name WHERE id = 1;

针对字段建立索引

CREATE INDEX index_name on table_name;

再执行,查看耗时

建立哈希索引

ALTER TABLE MyTable_memop
ADD INDEX ix_hash_Column2 UNIQUE
HASH (Column2) WITH (BUCKET_COUNT = 64);

哈希索引桶计数在索引创建时指定,可使用ALTER TABLE...ALTER INDEX REBUILD语法进行更改。

在大多数情况下,桶计数在理想情况下应该介于索引键中非重复值数目的 1 到 2 倍之间。

单列索引与联合索引

关联一个字段——单列索引;
关联多个字段——联合索引(组合索引)(联合索引中字段的顺序——最左前缀法则)
涉及多个查询条件时,建议使用联合索引

索引失效

最左前缀法则:

查询时从索引的最左列开始,且不跳过索引中的列。如果跳过了,跳过之后的列会失效

范围查询:

在联合索引中,出现范围查询(<,>,between),范围查询之后的列失效

覆盖索引:

查询返回的列在索引中都包含

其他索引失效

在索引列里进行运算操作,索引会失效
类型转换导致索引失效——不给字符串类型加单引号,索引失效
模糊匹配:在头部进行模糊匹配,索引会失效。在尾部进行不会
Or连接:只有所有条件都有索引,索引才会执行
is null可以使用索引,is not null无法使用索引

索引分布影响

如果数据库评估全表查询比使用索引更快,则不使用索引

索引提示

如果数据库评估全表查询比使用索引更快,则不使用索引

前缀索引

scan/seek

全表扫描与索引查找的磁盘 I/O

  • Table Scan 的 Disk I/O
  • Nonclustered Index Scan 的 Disk I/O
  • Clustered Seek 的 Disk I/O
  • Nonclustered Index Seek 的 Disk I/O

index seek是查找从B树的根节点开始,一级一级找到目标行。
index scan则是从左到右,把整个B树遍历一遍

SQL有一个查询优化分析器 Query Optimizer,其在执行查询之前首先会进行分析,当查询中有可以利用的索引时,其会优先分析使用Index Seek进行查询的效率,在使用Index Seek查询效率并不好的情况下,其会使用Index Scan进行查询。
1.在要查询的表中数据不是很多的话,使用Index Seek效率不一定高,因此使用Index seek还要先从索引树开始,然后再利用叶子节点去查找相应的行。在行树比较少的情况下,还没有直接进行Index scan快。
2.在返回的数据量大的情况下,在返回的数据量占总数据量的50%或者超过50%则使用Index Seek效率不一定好,在返回的数据量占10%-15%时,利用Index Seek能获得最佳的性能。
3.在建立索引的列的取值很多是一致的情况下,建立索引不一定能获得很好的效率。

利用统计优化查询

引入关键字(MySQL)

  • DBCC SHOW_STATISTICS
  • CREATE STATISTICS / DROP STATISTICS

索引设计原则

  • 数据量大
  • 查询频繁
  • 常使用where(查询)、order by(排序)、group by(分组)
  • 尽量选择区分度高的字段作为索引,尽量建立唯一索引
  • 尽量使用联合索引,联合索引可以实现覆盖索引,减少回表查询
    索引越多,维护索引的代价越大,增删改的效率会降低——只建立必要的索引
    索引不能储存NULL,因此在创建表示要使用NOT NULL约束。当优化器知道每列是否包含NULL时,可以更好地确定使用哪个索引
<think>嗯,用户问的是数据库索引底层原理。我需要先回忆一下相关知识,确保自己理解正确。数据库索引通常使用B树、B+树、哈希表或者LSM树这些结构。其中,B+树在关系型数据库中最常见,比如MySQL的InnoDB引擎。 首先,用户可能是一个刚开始学习数据库的开发者或者学生,他们可能对索引为什么能加快查询速度感兴趣。需要解释清楚索引的数据结构,以及这些结构如何影响查询效率。 接下来要考虑用户的实际需求。他们可能想知道如何优化数据库性能,或者遇到慢查询问题想了解索引的工作原理。这时候需要不仅讲理论,还要结合实际应用,比如索引的选择、维护成本,以及不同场景下的适用性。 然后,用户可能存在的深层问题包括:为什么有时候索引没有生效?如何设计合适的索引?或者索引带来的开销有哪些?这些问题需要在回答中提及,比如提到最左匹配原则、覆盖索引,以及索引的维护代价如插入删除时的平衡操作。 需要避免使用太多专业术语,用通俗易懂的语言解释。比如B+树的结构,可以比喻为多层的目录,每层有多个键值,这样查找时能快速定位到数据所在的位置。同时,对比不同结构的优缺点,比如哈希表适合等值查询但范围查询效率低,而B+树适合范围查询。 还要注意回答的结构,分点说明,让读者容易理解。先讲常见的索引结构,再深入B+树的细节,最后讨论使用场景和维护注意事项。这样逻辑清晰,逐步深入。 另外,用户可能对InnoDB的聚集索引和二级索引的区别不太清楚,需要解释清楚聚集索引的叶子节点存储的是数据行,而二级索引存储的是主键值,这样在回表查询时的过程。 最后,提醒用户索引虽然重要,但不可滥用,要考虑写操作的性能影响,以及如何根据查询模式选择合适的索引。这部分可以帮助用户在实际应用中避免常见错误,比如创建过多索引导致插入变慢。 总结一下,回答需要涵盖索引底层数据结构、工作原理、优缺点,以及实际使用中的注意事项,帮助用户全面理解索引的机制和应用。</think>以下是关于数据库索引底层原理的详细介绍,采用结构化表述方式: --- ### 一、核心数据结构 1. **B+树(主流选择)** - 多叉平衡搜索树,典型应用于MySQL InnoDB - 结构特征: $h$层高度可存储$n^{h}$个数据($n$为节点容量) 叶子节点形成有序双向链表 非叶子节点仅存储键值和指针 - 查询复杂度:$O(\log n)$ 2. **B树(对比参考)** - 所有节点存储数据 - 更适合内存数据库 - 更新代价低于B+树 3. **哈希索引(特殊场景)** - 时间复杂度$O(1)$ - 仅支持等值查询 - InnoDB自适应哈希索引 4. **LSM树(日志结构合并树)** - 应用于LevelDB/RocksDB - 顺序写优化 - 通过Compaction合并数据 --- ### 二、B+树深度解析 ![B+树结构示例](https://example.com/bplus-tree.png)*(示意图:3层B+树结构)* 1. **节点组成** - 非叶子节点: $[ (key_1, ptr_1), (key_2, ptr_2), ..., (key_m, ptr_m) ]$ - 叶子节点: $[ (key_1, data_1), ..., (key_n, data_n), next_ptr ]$ 2. **插入过程** - 定位叶子节点 → 插入数据 → 节点分裂(超过容量) → 向上递归调整 3. **范围查询优化** ```sql SELECT * FROM table WHERE id BETWEEN 100 AND 300 ``` - 通过叶子节点链表直接遍历,避免回溯非叶子节点 --- ### 三、存储引擎实现差异 | 特性 | InnoDB | MyISAM | |---------------------|--------------------|----------------| | **索引类型** | 聚集索引 | 非聚集索引 | | **数据存储** | 主键索引含完整数据 | 独立.MYD文件 | | **二级索引** | 存储主键值 | 存储数据指针 | | **锁粒度** | 行级锁 | 表级锁 | --- ### 四、关键性能指标 1. **索引选择性** $Selectivity = \frac{distinct(column)}{total\_rows}$ 选择性>30%时考虑建立索引 2. **索引覆盖度** ```sql -- 需要回表 SELECT * FROM users WHERE age > 25 -- 覆盖索引 SELECT name FROM users WHERE age > 25 ``` 3. **页分裂代价** - B+树节点通常对应4KB/16KB磁盘页 - 页填充因子(fill factor)控制空间利用率 --- ### 五、实践注意事项 1. **最左前缀原则** 联合索引`(a,b,c)`有效场景: - WHERE a=1 AND b>2 - ORDER BY a,b,c 失效场景: - WHERE b=5 AND c=10 - WHERE a=1 ORDER BY c 2. **索引维护代价** - INSERT:树平衡操作$O(\log n)$ - UPDATE:可能引起页分裂 - DELETE:标记删除或空间回收 3. **监控指标** ```sql SHOW STATUS LIKE 'Handler_read%'; -- Handler_read_key:索引命中次数 -- Handler_read_rnd_next:全表扫描次数 ``` --- ### 六、新型索引发展 1. **列式存储索引**(ClickHouse) 2. **向量化索引**(相似性搜索) 3. **空间索引**(R树/GIS应用) 4. **倒排索引**(全文搜索) --- 通过理解底层机制,可以更好把握: 1. 索引选择策略(B+树 vs 哈希) 2. 查询计划优化(EXPLAIN分析) 3. 冷热数据分离设计 4. 分布式索引架构(如Elasticsearch分片)
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sevenlob

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值