AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 211762
Accepted
John K. N.
John K. N.
Asked: 2018-07-11 06:12:23 +0800 CST2018-07-11 06:12:23 +0800 CST 2018-07-11 06:12:23 +0800 CST

页眉中还存储了哪些其他信息

  • 772

SQL Server 数据库页的大小定义为 8192 字节。有一些标头信息据说大小为 96 字节。

如果您曾经尝试创建一个包含超过 8053 字节的列定义的表,那么您将遇到错误消息:

Creating or altering table 'Generated_Data_GUID' failed because the 
minimum row size would be 8061, including 7 bytes of internal overhead. 
This exceeds the maximum allowable table row size of 8060 bytes.

以下是一个示例表 DDL:

CREATE TABLE [dbo].[Generated_Data_GUID](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [GUID] [uniqueidentifier] NOT NULL,
    [SEQGUID] [uniqueidentifier] NOT NULL,
    [Data1] [char](4000) NULL,
    [Data2] [char](4000) NULL,
    [Data3] [char](9) NULL,
    [EntryDate] [datetime2](7) NULL
) ON [PRIMARY]

使用上面的 DDL,如果我将列的列定义更改为Data3,char(10)那么我将遇到错误消息。

每种列类型的字节大小如下:

int               :  4 bytes
uniqueidentifiere : 16 bytes
char(n)           :  n bytes
datetime2(n)      :  6 bytes if n < 3 
                     7 bytes if n = 3 or n = 4
                     8 bytes if n > 4

如果我们做一些简单的数学运算,那么我们最终会得到以下计算:

Page Size         : 8192 bytes
                   -----------
Header            :   96 bytes - 
Internal Overhead :    7 bytes - 
Max Size          : 8053 bytes - 
                   -----------
Missing Data      :   36 bytes
                   ===========

问题

这 36 个字节包含什么?

参考资料

  • 页面和范围架构指南(Microsoft 文档)
  • 存储引擎内部:页面剖析(SQLSkills.com)
sql-server sql-server-2012
  • 1 1 个回答
  • 595 Views

1 个回答

  • Voted
  1. Best Answer
    Josh Darnell
    2018-07-11T07:40:38+08:002018-07-11T07:40:38+08:00

    Paul Randal 实际上在您链接到的博客文章的评论中回答了这个确切的问题:

    8060 字节是一条记录的最大大小,而不是页面上的数据空间量——8096 字节。

    对于 8060 字节的最大记录,为插槽数组条目添加两个字节,为可能的堆转发记录反向指针添加 10 个字节,为可能的版本控制标签添加 14 个字节,这样就使用了 26 个字节。其他 10 个字节供将来使用。

    如果页面上有多条记录,则可以使用所有 8096 字节的数据空间。

    因此,在回答您帖子正文中的问题时:

    这 36 个字节包含什么?

    页中“额外”的 36 个字节使用如下:

    • 为堆前向记录后向指针保留 10 个字节
    • 为指向 tempdb 中版本存储的版本标记保留 14 个字节
    • 12 个字节可用于插槽数组
      • 如果您概述了一条大记录,则此处有 10 个字节的“浪费”空间。还有 5 个 2 字节槽数组条目的空间

    只是为了确认问题中定义的表实际上是 8060 字节宽,让我们进行完整的重现。

    首先,我们将设置数据库和表,并向其中插入一行。我正在添加聚集索引,因为堆是最糟糕的。

    USE master;
    GO
    
    CREATE DATABASE PageJunk;
    GO
    
    USE PageJunk;
    GO
    
    CREATE TABLE [dbo].[Generated_Data_GUID](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [GUID] [uniqueidentifier] NOT NULL,
        [SEQGUID] [uniqueidentifier] NOT NULL,
        [Data1] [char](4000) NULL,
        [Data2] [char](4000) NULL,
        [Data3] [char](9) NULL,
        [EntryDate] [datetime2](7) NULL
    ) ON [PRIMARY];
    GO
    
    CREATE CLUSTERED INDEX PK_Generated_Data_GUID 
        ON Generated_Data_GUID (ID);
    GO
    
    INSERT INTO [dbo].[Generated_Data_GUID]
        ([GUID], SEQGUID, Data1, Data2, Data3, EntryDate)
    VALUES
        (NEWID(), NEWID(), REPLICATE('1', 4000), REPLICATE('2', 4000), REPLICATE('3', 9), '2018-01-01');
    GO
    

    通过运行以下 DBCC 命令,我们可以看到所有分配了索引的页面:

    DBCC IND ('PageJunk', 'Generated_Data_GUID', 1);
    GO
    

    神秘的 dbcc 废话

    页面类型为 1 的页面是索引页面(页面 ID 336)。我们可以使用其他 DBCC 命令转储有关该页面的各种信息:

    DBCC TRACEON (3604); -- needed for the next one to work
    GO
    
    DBCC PAGE (PageJunk, 1, 336, 3);
    GO
    

    以下是该命令输出的一些重要片段。从标题部分:

    m_freeCnt = 34
    

    这意味着页面上有 34 个字节的可用空间。这是您在原始帖子中概述的 36,减去插槽数组条目的 2 个字节。说到其中:

    m_slotCnt = 1
    

    这意味着此页面上只有一条记录。

    现在,在记录部分:

    Slot 0 Offset 0x60 Length 8060
    
    Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 8060
    

    这表明存储在此页面上的单个记录为 8060 字节(这是所有数据类型存储大小的总和加上每条记录 7 字节的开销)。

    所以我们在这个页面上确实有一个全尺寸的 8060 字节记录。然而,如果我们更努力地尝试,我们仍然可以将额外的 34 个字节挤到这个页面上。

    例如,我可以创建一个 2015 字节宽的表。每行将占用页面中的 2015 + 7(内部开销)+ 2(槽数组)= 2024 字节。所以四行加起来应该是 8096 字节,恰好填满了 96 字节标头之后剩下的空间。让我们在同一个数据库中尝试一下:

    CREATE TABLE [dbo].[QuarterPage](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [GUID] [uniqueidentifier] NOT NULL,
        [SEQGUID] [uniqueidentifier] NOT NULL,
        [Data1] [char](981) NULL,
        [Data2] [char](981) NULL,
        [Data3] [char](9) NULL,
        [EntryDate] [datetime2](7) NULL
    ) ON [PRIMARY];
    GO
    
    CREATE CLUSTERED INDEX PK_QuarterPage
        ON QuarterPage (ID);
    GO
    
    INSERT INTO [dbo].[QuarterPage]
        ([GUID], SEQGUID, Data1, Data2, Data3, EntryDate)
    VALUES
        (NEWID(), NEWID(), REPLICATE('1', 981), REPLICATE('2', 981), REPLICATE('3', 9), '2018-01-01');
    GO 4
    

    现在我们找到我们的页面,并且只有一个页面:

    DBCC IND ('PageJunk', 'QuarterPage', 1);
    GO
    

    更多 dbcc 废话

    所以现在我们想获取第 352 页的信息:

    DBCC PAGE (PageJunk, 1, 352, 3);
    GO
    

    这是好东西:

    m_slotCnt = 4
    m_freeCnt = 0
    

    没有可用空间!这个页面充满了我们的 4 行。

    • 10

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve