Sql server 了解sp_spaceused值:保留和索引_大小
我正在运行以下简单脚本:Sql server 了解sp_spaceused值:保留和索引_大小,sql-server,allocation,Sql Server,Allocation,我正在运行以下简单脚本: create table MyTable (filler char(10)) go insert into MyTable (filler) values ('a') go 1 exec sp_spaceused MyTable go drop table MyTable go 并得到如下结果: rows reserved data index_size unused ------ ---------- ------ -----------
create table MyTable (filler char(10))
go
insert into MyTable (filler) values ('a')
go 1
exec sp_spaceused MyTable
go
drop table MyTable
go
并得到如下结果:
rows reserved data index_size unused
------ ---------- ------ ----------- -------
1 72 KB 8 KB 8 KB 56 KB
我的问题是:
create table MyTable (filler char(69))
go
insert into MyTable (filler) values ('a')
go 100
我得到:
rows reserved data index_size unused
------ ---------- ------ ----------- -------
100 72 KB 16 KB 8 KB 48 KB
请注意,将filler
的大小定义为68字节(并插入100行)仍然会给出8KB作为数据的值(我们可以继续并将其设置为148字节,这将导致另一个8KB的增量,即24KB)
你能帮我把计算结果分解一下吗?如果(显然)只使用了6900字节,那么8KB的增加是什么原因
编辑#2:
以下是DBCC页面的结果:
PAGE: (1:4392)
BUFFER:
BUF @0x00000000061A78C0
bpage = 0x00000001EF3A8000 bhash = 0x0000000000000000 bpageno = (1:4392)
bdbid = 6 breferences = 0 bcputicks = 0
bsampleCount = 0 bUse1 = 18482 bstat = 0x9
blog = 0x15ab215a bnext = 0x0000000000000000 bDirtyContext = 0x0000000000000000
bstat2 = 0x0
PAGE HEADER:
Page @0x00000001EF3A8000
m_pageId = (1:4392) m_headerVersion = 1 m_type = 1
m_typeFlagBits = 0x0 m_level = 0 m_flagBits = 0x8200
m_objId (AllocUnitId.idObj) = 260 m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594054967296
Metadata: PartitionId = 72057594048151552 Metadata: IndexId = 0
Metadata: ObjectId = 1698105090 m_prevPage = (0:0) m_nextPage = (0:0)
pminlen = 72 m_slotCnt = 100 m_freeCnt = 396
m_freeData = 7596 m_reservedCnt = 0 m_lsn = (55:8224:2)
m_xactReserved = 0 m_xdesId = (0:0) m_ghostRecCnt = 0
m_tornBits = -2116084714 DB Frag ID = 1
Allocation Status
GAM (1:2) = ALLOCATED SGAM (1:3) = NOT ALLOCATED PFS (1:1) = 0x44 ALLOCATED 100_PCT_FULL
DIFF (1:6) = CHANGED ML (1:7) = NOT MIN_LOGGED
Slot 0 Offset 0x60 Length 75
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 75
Memory Dump @0x0000000012A3A060
0000000000000000: 10004800 61202020 20202020 20202020 20202020 ..H.a
0000000000000014: 20202020 20202020 20202020 20202020 20202020
0000000000000028: 20202020 20202020 20202020 20202020 20202020
000000000000003C: 20202020 20202020 20202020 010000 ...
Slot 0 Column 1 Offset 0x4 Length 68 Length (physical) 68
filler = a
-- NOTE: The structure of each Slot is identical to that of Slot #0, so we can simply jump to slot 99:
Slot 99 Offset 0x1d61 Length 75
Record Type = PRIMARY_RECORD Record Attributes = NULL_BITMAP Record Size = 75
Memory Dump @0x0000000012A3BD61
0000000000000000: 10004800 61202020 20202020 20202020 20202020 ..H.a
0000000000000014: 20202020 20202020 20202020 20202020 20202020
0000000000000028: 20202020 20202020 20202020 20202020 20202020
000000000000003C: 20202020 20202020 20202020 010000 ...
Slot 99 Column 1 Offset 0x4 Length 68 Length (physical) 68
filler = a
我们可以看到最后一个插槽在7521字节之后开始,加上它的大小,我们得到了7596字节。如果我们添加插槽数组的大小(其中每个指针为2个字节),我们将得到7796个字节
然而,我们需要得到8192字节来填充页面。少了什么 72K的保留空间包括64K扩展数据块(8页,每个8K)加上8K IAM页面开销。在这72K中,实际上只使用IAM页和单个数据页sp_space_used
以索引大小报告IAM页面,尽管从技术上讲不是索引。您可以在未记录的sys.dm\u db\u数据库\u页面\u分配中查看这些详细信息(仅在测试系统上使用):
显然,该数据库的MIXED_PAGE_分配
database选项设置为OFF
,因此最初会分配一个完整的64K数据块。如果该选项处于启用状态,则单个数据页将从混合扩展数据块分配,而不是从表专用的64K扩展数据块分配。在这种情况下分配的空间为16K—8K单数据页加IAM页
尽管混合扩展数据块确实减少了小表(低于64K)的空间需求,但混合扩展数据块的开销更大,并且在高并发工作负载中可能会导致分配争用,因此在SQL 2016以后的版本中,它默认处于关闭状态。在较旧的SQL版本中,混合数据块分配在默认情况下处于打开状态,可以在服务器级别使用跟踪标志1118关闭
您可以在sys.databases
中看到混合数据块设置:
SELECT name, is_mixed_page_allocation_on
FROM sys.databases;
要切换设置,请执行以下操作:
ALTER DATABASE Test
SET MIXED_PAGE_ALLOCATION ON;
编辑1:
数据页内的空间包括页本身的开销以及页内的记录。这一开销,加上用户数据所需的空间,将决定一页上可以容纳多少行以及存储给定行数所需的数据页数。请参阅Paul Randal的和文章,了解该开销的详细信息
编辑2:
根据您的后续评论:
7998字节,因此下一次分配还有194个字节。
我错过了什么
我几乎从不使用堆,但正如您在页面转储中看到的,此页面的关联PFS(页面可用空间)分配状态为100%已满。根据本书,PFS状态实际上是这些范围的3位掩码:
- 000:空
- 001:1-50%满
- 010:51-80%满
- 011:81-95%满
- 100:96-100%满
所以看起来,一旦堆页面满度超过96%的阈值,它就被认为是100%满的,并分配了一个新页面。请注意,这不会发生在具有聚集索引的表上,因为新行的页面首先由CI键确定,并且仅当新页面根本无法放入该页面时才分配新页面。还有一个避免堆积的原因。谢谢。我编辑了这个问题以包含一个后续问题,如果您也可以参考它的话,那就太好了。@HeyJude,a为我的答案添加了一个解释。好吧,我正在尝试做数学计算:6900字节的普通数据+800字节(8*100)的记录头+2(或3?)字节的空位图+96字节的页面头+200字节(2*100)插槽数组指针的数量=7998字节,因此下一次分配还有194个字节。我错过了什么?(顺便说一句,不知什么原因,DBCC-PAGE
只对带有TABLERESULTS
的有效,这不是很方便,否则我会尝试更仔细地查看页面内容)。@HeyJude,你需要执行DBCC-TRACEON(3604)来查看没有TABLE_结果的DBCC-PAGE输出。谢谢,我添加了转储,也许你能告诉我我错过了什么。
ALTER DATABASE Test
SET MIXED_PAGE_ALLOCATION ON;