热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

SQLServer存储引擎

一、遍历索引树的每个节点都是一个页面。索引树有三种类型的节点:根节点、中间节点、叶子节点。(1)根节点与中间节点一样,只包含下一层节点的入口值与入口指针

一、遍历索引树的每个节点都是一个页面。索引树有三种类型的节点:根节点、中间节点、叶子节点。(1)根节点与中间节点一样,只包含下一层节点的入口值与入口指针

一、遍历

索引树的每个节点都是一个页面。

索引树有三种类型的节点:根节点、中间节点、叶子节点。

(1) 根节点与中间节点一样,只包含下一层节点的入口值与入口指针,它们称为索引节点;

(2) 叶子节点包含要遍历的数据,服务器空间,对聚集索引而言数据就是表中数据行,对非聚集索引数据是指索引列值和行书签。


索引的遍历总是从根节点开始,即先根遍历,分为两种:索引扫描和索引查找。

(1) 索引扫描,是指从索引树的根节点开始,对叶子节点逐个扫描,直至命中所有满足查找条件的数据;

(2) 索引查找,是指从索引树的根节点开始,按查找值在索引节点中根据路由信息跳转,直至叶子节点以命中数据。


B+树的深度通常小于等于3,计算如下:

以聚集索引为例,简单计算如下:10个INT列宽度总和为40B,假设聚集索引树每一层为二叉,共三层,即2^0+2^1+2^2=1*(1-2^3)/(1-2)=7个页面,4个叶子节点,每个页面8060K可存储8060000/40=201500行,乘以4=806000行,如果是三叉、四叉,那么三层可存储上千万至亿行的数据,当然在数据量达到这个等级时,通常我们会选择表分区,那么B树深度就更不会突破三层了。

所以索引查找的效率是很高的,在查询中应该努力构造索引查找,避免索引扫描。


二、插入

2.1、页空间充足

在已存在数据的表上,创建或重建索引时,可指定填充因子,即在索引树的每个节点上预留一定的空间,供表中后续增加的数据使用。但如果在创建表的时候就创建了索引,并指定了填充因子,这时的填充因子是无用的,数据库系统不会刻意去保留页面的空间。


索引页面有剩余空间的情况如下图:

图1

参考图1,此时向索引树中插入一条索引键值为31的记录,步骤如下:

(1)执行索引键值=31的查找操作,确定该新记录应该插入到叶子节点L2中。

(2)检查L2上是否有足够的空间来存放当前记录,这里假设有足够的空间;

(3)将记录45向后移动,插入索引键值为31的新记录。插入之后,10、30、31、45还是顺序的,香港服务器,如下图:


图2

2.2、页空间不足

参加图2,此时再插入一条索引键值为32的记录,步骤如下:

(1)执行索引键值=32的查找操作,确定该新记录应该插入到叶子节点L2中;

(2)检查L2上是否有足够的空间来存放当前记录,这时发现没有足够的页空间,香港服务器,此时需要进行页面分裂;

(3)向数据库系统申请一个新的页面L4,将L2的一半数据移到L4中,并重新链接叶子的左右节点,如下图:


图3

(4)此时,上层节点也需要生成一个新的叶子节点的指针。这里的上层节点即根节点,如果上层节点没有剩余空间的话,同样也需要进行分裂,这里有剩余空间,如下图:


图4

(5)因为当前记录的键值范围位于页分裂的后一半中,将索引键值为32的新记录插入到L4中,如果键值范围位于前一半,则插入到L2中。如果L4的空间不够存放键值为32的新记录,则L4会继续进行页分裂,这里假设空间足够,插入结束,如下图:


图5

三、删除

3.1、删除叶子节点中的记录

参考图5,删除索引键值为32的记录,步骤如下:

(1)执行索引键值=32的查找操作,确定该记录在L4中;

(2)将索引键值=32的记录标记为虚影,但并不立即释放空间,虚影记录可用于事务回滚、多版本等;

(3)如果此时L4上的虚影记录空间被申请使用,虚影记录就会被擦除;

(4)如果数据页面最后一条记录也被删除,数据页面会被回收;


3.2、删除非叶子节点中的记录

(1)索引节点中的指针被删除时并不是虚影记录,但同样也不释放空间,直到有新的指针插入时,才会进行空间压缩;

(2)堆表中数据行被删除后,页空间不会被回收,即使是空闲分页也还是标识为分配状态,无法被其他对象使用;


注:从理论上讲,在兄弟节点页面空闲空间都小于50%时,应该将兄弟节点合并,即分裂的逆操作,但这样可能带来的后果是更频繁的页面合并、分裂,成本更大,所以在数据库系统中通常不进行页面合并操作,除非rebuild/reorganize索引。


四、更新

4.1、覆盖更新

如果更新操作能够在页内进行原位键值替换,那么就进行覆盖更新。


4.2、非覆盖更新

无法进行覆盖更新时,更新操作被分解为删除和插入操作。


如果非覆盖更新过程中,新的记录比较长,则会在页面分裂的过程中会带来数据行的移动:

(1)聚集索引的移动对非聚集索引没有影响,因为非聚集索引中存储的是聚集索引的键值,分裂并不会改变键值;

(2)堆表中的数据页分裂,会在原记录处留下一个前转指针,以告诉非聚集索引去哪里找新的记录;

所以数据行的移动对非聚集索引都不会带来维护的成本,非聚集索引的维护成本来自书签的变化:

(1)聚集索引的键值发生变化或被删除;

(2)堆表中的数据行被删除。


本文出自 “SQL Server DBA” 博客,请务必保留此出处

推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 在Kubernetes上部署JupyterHub的步骤和实验依赖
    本文介绍了在Kubernetes上部署JupyterHub的步骤和实验所需的依赖,包括安装Docker和K8s,使用kubeadm进行安装,以及更新下载的镜像等。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • Oracle分析函数first_value()和last_value()的用法及原理
    本文介绍了Oracle分析函数first_value()和last_value()的用法和原理,以及在查询销售记录日期和部门中的应用。通过示例和解释,详细说明了first_value()和last_value()的功能和不同之处。同时,对于last_value()的结果出现不一样的情况进行了解释,并提供了理解last_value()默认统计范围的方法。该文对于使用Oracle分析函数的开发人员和数据库管理员具有参考价值。 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
author-avatar
感伤花沙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有