zoukankan      html  css  js  c++  java
  • [译]SQL Passion Week 2: SQL Server的基本存储单位--数据页

    Week 2: SQL Server的基本存储单位--数据页

     

      上周我们我们讲述了SQL Server如何执行一个查询, 顺带提到了数据页的概念, 这次我们从性能调优的角度上更详细深入的讲解一些数据页.

     

      数据页是SQL Server最基础的存储单位, 所有的东西都和数据页有关. 当我们想提高查询的性能时, 必须想方设法降低查询的页读取数量. 以后讲到索引时, 还会涉及到更多索引的结构. 如果你不知道什么是页, 你就无法寻找SQL Server的故障原因.

     

      数据页的结构

      SQL Server中的页有不同类型:数据页,索引页,系统页等等, 但每个页的大小都为8KB. 我们主要讲一下用来存储表数据的数据页, 一个数据页包含三个部分

    1. 页头 Page Header
    2. 数据装载区 Payload      
    3. 行偏移数组 Row Offset Array

      页头的长度为96bytes(取决于页的类型),页头一般放置了Page ID, Object ID等信息; 页最重要的部分在数据装载区, 我们的数据记录就是存储在这个区域.

      整个页的大小为8kb即8192bytes,去掉页头,我们总共的用来存储数据的空间就是8096bytes,这其中还包含了至少7bytes的行偏移数组.

      所以要计算出一个页上存储了多少行记录比较简单, 只要用8096除以表的列长度之和就可以大约算出来了. (注: 这里包括后面的计算有一定谬误, SQL Server会自动为页保留一些空间以备扩展, 计算结果会有较大偏差)

      SQL Server的读写都是基于一个完整的页, 不能只读写页的一部分, 所以一个数据页能存储的行数越多越好, 这意味着同样的数量下,可以降低数据库需要读写的页数.

      请牢记: SQL Server的IO操作是页级别

      数据页的最后部分就是Row Offset Array, 该部分为每条数据记录存储一个2bytes的值来指明记录的位置. 第一条记录永远是96的位置, 因为第一条记录在page header的后面.

      下图就是数据页的结构示意图:

      

      数据页内部解析

      让我们先看一个简单的表结构, 下面是创建语句:

       

    CREATE TABLE Customers
    (
       FirstName CHAR(50) NOT NULL,
       LastName CHAR(50) NOT NULL,
       Address CHAR(100) NOT NULL,
       ZipCode CHAR(5) NOT NULL,
       Rating INT NOT NULL,
       ModifiedDate DATETIME NOT NULL,
    )
    GO

      通过表的定义我们能很轻松的计算出一个数据页上存储了多少条记录.

      每天记录长度为: 50 + 50 + 100 + 4 + 8 + 9 + 7 = 224bytes,

      一个页上能存储 8096 / 224 = 36.14 条记录.

      实际上一个页上存储了36条记录,即占用了224 * 36 = 8064 bytes,

      剩余的32bytes不在存储任何东西, 因为一个页只能属于一个数据库对象(在这里只属于Customers表)! 最坏的情况是什么呢, 想象一下我们的表每条记录如果有4031bytes, 那就是每一个数据页都浪费了4029bytes的空间. 通常我们可以使用varchar类型来应对这种情况, SQL Server允许列可以存储在不同的页上.

      如果你想知道某个表结构浪费了多少页空间, 可以通过系统视图: sys.dm_os_buffer_descriptors 来查看.

    SELECT
       DB_NAME(database_id),
       SUM(free_space_in_bytes) / 1024 AS 'Free_KB'
    FROM sys.dm_os_buffer_descriptors
    WHERE database_id <> 32767
    GROUP BY database_id
    ORDER BY SUM(free_space_in_bytes) DESC
    GO

      每条记录都代表当前存储在buffer pool中的页, 请注意, 调用此视图会占用相当多的内存.

      free_space_in_bytes 列表示当前页的剩余空间, 通过上面的语句, 我们可以查询出当前的实例中, 每个数据库所浪费空间的排名.  以此来找出哪些数据库里可以存在比较烂的表设计.

      

      

  • 相关阅读:
    java基础知识:私有成员变量
    分布式架构:概述一
    java基础知识:内存
    原油期货价格跌至-37美元/桶的影响
    贷款利息
    java基础知识:IntelliJ IDEA的基础设置
    正则表达式的常用方法
    http服务器三:自己写一个服务器实现转发功能
    bzoj3875: [Ahoi2014&Jsoi2014]骑士游戏(用spfa解决有后效性的dp)
    bzoj2118: 墨墨的等式(巧妙的单源最短路+priority_queue)
  • 原文地址:https://www.cnblogs.com/alphaqcode/p/4981076.html
Copyright © 2011-2022 走看看