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

深入理解Sqlserver文件存储之页和应用-mysql教程

我们每天都在使用数据库,我们部门使用最多的关系数据库有Sqlserver,Oracle,有没有想过这些数据库是怎么存放到操作系统的文件中的?有时候为了能够设计出最优的表结构,写出高性能的Sqlserver脚本,处理海量数据并发,我们必须解底层原理。由于个人

我们每天都在使用数据库,我们部门使用最多的关系数据库有 Sqlserver , Oracle ,有没有想过这些数据库是怎么存放到操作系统的文件中的?有时候为了能够设计出最优的表结构,写出高性能的 Sqlserver 脚本,处理海量数据并发,我们必须解底层原理。由于个人

我们每天都在使用数据库,我们部门使用最多的关系数据库有SqlserverOracle,有没有想过这些数据库是怎么存放到操作系统的文件中的?有时候为了能够设计出最优的表结构,写出高性能的Sqlserver脚本,处理海量数据并发,我们必须解底层原理。由于个人兴趣最近研究了下Sqlserver的文件存储,由于水平有限,下面只讲解Sqlserver的最小存储单元-页。

什么是页,区?

什么会有一个页的概念,我们知道对于操作系统来说,文件可以认为是一个很大的线性空间,如果按地址空间顺序分配容量(也就是按段式存储),则有可能会造成很多的外部碎片,造成很多的容量很难再次使用,只有移动合并空间才能腾出更多的空间。例如:如下表所有,如果我现在要申请1024B字节的空间,显然下面的两个空间空间单个计算不够,合起来却是够用的的,只能移动合并空间。

8KB

512B

12KB

512B

8KB

已分配空间

空闲

已分配空间

空闲

已分配空间

1

为了能够更好的利用磁盘空间,Sqlserver借鉴了操作系统的虚拟内存的概念,人为的将文件划分N8KB的存储空间,这样每次分配时,都是按照8KB空间申请,就解决了外部碎片的问题,也就是说Sqlserver 中数据存储的基本单位,页的大小为8KB,每页的开头是96字节的标头用于存储有关页的存储信息,其中有页码、页类型、页的可用空间以及拥有该页对象的分配单元ID。上述的例子分配就成为下表所示:这样就解决了外部碎片问题。

业内分配

8kB

12KB

8KB

xxKB

页单元

8KB

8KB

8KB

8KB

空闲

2

为什么会有区的概念,已经有了页的单位难道不够吗?主要是为了更好的管理这些空间,Sqlserver将每8个页划分为一个区(如下表所示)就像百元大钞代表着10010元人民币一样,出去买很多东西时,用百元大钞比用很多1元钱要方面。

一个分区

1

2

3

4

5

6

7

8

3

为了有个页有更具体的认识,下表为页头的结构:

-1

行是怎么在页中存储的?

那么数据库中的数据到底是以什么样的形式存储在数据中的呢?Sqlserver是以行为单位存储的数据,也就是说表中的每条数据(每行数据为一个块)顺序存放在页中的,那么怎么找到行?也就是一行的开始地址和结束地址? Sqlserver在每页的末尾以2个字节为单位存放了每行的开始地址,这样我们就可以定位到行的开始,通过下一条的开始位置能够知道本条记录的结束位置,这样我们就可以取出这行数据了。

-2

如图所示,如果我想取第二条数据,那么现将一页数据都读到内存中,然后从最后读取偏移为第3开始开始读取2个字节,怎么可以找到行2的开始位置,同理可以读取出行2的结束位置。

列是怎么在页中的存储?

现在我们已经读取到行了并且已经在内存里了,接下来怎么解析出一行中的所有列?也就是这些列是怎么存放的?数据库表中的列无非就两种情况:定长列、变长列。

首先假设只有定长列,那么很容易想到一样中的每列的之顺序存放就行了,因为是定长的,完全可以将每列的偏移放到另外一个地方单独存储,如果要取某个特定的列,每个列的位置很容易定位:如下表所示:

2字节

3字节

6字节

10字节

3字节

2字节

1

23

55

A

C

D

-4

如果要取红色的数据,那么它的

开始位置=(行开始位置)+ 2字节+3字节+6字节+10字节。

结束位置= 开始位置 + 3字节。

其中每个列的长度完全可以用另一张表存放

1

2

3

4

5

6

长度(字节)

2

3

6

10

3

2

-5

具体行结构的详细信息如下:

-3

假如设计的表结构为 :

Col1

Col2

Col3

Col4

Char(5)(not null)

Int (null)

Char(3)(null)

Char(6)(not null)

-6

在数据库中存放数据为:

Col1

Col2

Col3

Col4

‘ABCDE’

‘123’

‘null’

‘ccc ‘

-7

则数据在数据库文件中数据以如下形式存在:

-4

如果其中有变长列呢,这个结构又是怎么存储的?有变长列最大的不同就是每个列的长度是不定的(同一列,每行长度都不一样),也就是不能用另外一张表存放。那么我们只能把列的长度放在行内了。这样就解决了实际长度定位的问题,上面已经说过,sqlserver有一个行偏移矩阵。

如果我们定义的表结构如下:

Col1

Col2

Col3

Col4

Col5

Char(2)(not null)

Varchar(250)(not null)

Varchar(5)(null)

Varchar(20)(not null)

Small int (null)

-8

假如这行数据为:

Col1

Col2

Col3

Col4

Col5

AAA

RELICATE(‘X’,250)

null

‘ABC’

123

-9

则数据在数据库中实际的存放形式为:


-5

结论:

1.数据库列中尽量不用可空类型,当值为空时,实际不占用位置,并且也不能作为索引的键值。导致where语句中含有 is null 或者 is not null 时只能进行全表扫描,并且可空类型也容易导致空引用异常。

2.在设计列时,只有列长度确定的才用定长,比如身份证。其他情况基本上应该用varchar边长类型,不但节省空间的同时,一个页存放的数据会变多。导致同样的数据量读取页的次数变少,减少I/O,提高性能。

3.如图-1所示,聚簇索引不是按物理顺序存放的,是按逻辑物理顺序存放的(大多数人在这里会有误解。)

4.正常情况下不要使用varchar(max),因为这个列的数据肯定放不在一个页里,为了解决这个问题,sqlserver在列里只存放了一个指针。真正的数据放在了其他多个页里。每读取一行中的列都会至少多一次I/O,影响性能。

附注,参考资料:

(1) Microsoft SQL Server 2005技术内幕:存储引擎(中文)

(2)微软MSDN: http://msdn.microsoft.com/zh-cn/library/ms190969(v=sql.105).aspx

推荐阅读
  • ThinkPHP 文件缓存组件详解与应用
    本文深入探讨了ThinkPHP框架中的文件缓存类实现,提供了详细的代码示例和使用说明,旨在帮助开发者更好地理解和利用这一功能来优化应用程序性能。 ... [详细]
  • 本文档详细介绍了服务器与应用系统迁移的策略与实施步骤。迁移不仅涉及数据的转移,还包括环境配置、应用兼容性测试等多个方面,旨在确保迁移过程的顺利进行及迁移后的系统稳定运行。 ... [详细]
  • 睿智汇海教育致力于培养杰出的IT专业人才,确保学员在就业市场上具备竞争力,助其实现职业成功。我们提供的C#/.Net/Asp.Net培训课程,旨在通过系统的教学和丰富的实践机会,帮助学员掌握最新的技术知识。 ... [详细]
  • 统一幻灯片标题:使用母版功能的技巧
    本文详细介绍了如何通过PowerPoint中的幻灯片母版功能,实现所有幻灯片标题的一致性设置。同时,提供了其他办公软件和编程相关的实用技巧。 ... [详细]
  • MySQL 5.7 绿色版安装及 my.ini 配置详解
    本文主要针对最近因系统重装导致的MySQL配置问题,详细介绍了MySQL 5.7.24绿色解压版的安装步骤及my.ini配置文件的关键设置,帮助用户顺利完成数据库的安装与配置。 ... [详细]
  • 本文介绍如何利用JavaScript在页面加载时为ASP.NET的DropDownList控件设置特定的选项值。 ... [详细]
  • MyBatis入门指南
    本文详细介绍了MyBatis的基础知识,包括如何整合日志框架(如log4j和logback),使用外部JDBC文件,getMapper()方法的应用,以及别名设置等技巧。 ... [详细]
  • 在使用 SQL 语句从数据库中提取数据并尝试将其转换为其他数据类型时,可能会遇到 'java.math.BigDecimal cannot be cast to java.lang.Integer' 错误。本文将详细解释这一错误的原因,并提供有效的解决方案。 ... [详细]
  • 本文探讨了如何利用脚本文件高效管理Oracle数据库,包括脚本文件的创建、编辑及运行方法,旨在为数据库管理人员提供实用指导。 ... [详细]
  • 使用H5在前端生成Excel文件的方法
    本文介绍了一种利用HTML5和JavaScript库在浏览器端直接生成并下载Excel文件的技术方案。通过引入alasql.js和xlsx.core.min.js两个库,可以轻松实现数据导出功能。 ... [详细]
  • 本文介绍了一种方法,用于创建一个包含中文数据的 Employees 表,并确保在 SQL Server 中能够正确显示和处理中文字符。 ... [详细]
  • CentOS 7.6环境下Oracle 11g的数据泵操作与nmon性能监控
    本文详细介绍在CentOS 7.6操作系统中使用Oracle 11g的数据泵(Data Pump)进行数据的导入导出操作,并介绍如何通过nmon工具进行系统性能的监控与分析。 ... [详细]
  • 本文档详细介绍了如何在MongoDB命令行中执行基本操作,包括数据库的选择与创建、文档的插入与查询、文档的更新与删除等。同时,还涵盖了条件查询、统计、模糊查询等高级功能。 ... [详细]
  • 本文探讨了SQL查询执行缓慢的多种可能因素,并提供了详细的解释和解决方案。 ... [详细]
  • 本文档详细规划了从基础到高级的软件测试学习路径,包括但不限于测试基础、Linux和数据库、功能测试、Python编程、接口测试、性能测试、金融项目实战、UI自动化测试等内容,旨在为初学者和进阶者提供全面的学习指导。 ... [详细]
author-avatar
江韦亭君733
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有