我试图理解SQL如何在我们将一些新记录插入表中时分配新数据页.
我在新的数据库中创建了一个名为Employee的示例表 -
Create Database TestDb
GO
Use TestDb
GO
Create table Employee (
EmployeeName char(1000)) GO
Insert into Employee values ('Employee1')
DBCC IND('TestDb','dbo.Employee',-1)
Run Code Online (Sandbox Code Playgroud)
运行DBCC后,我看到了2页.一个是IAM页面(PageType = 10),另一个是数据页面(PageType = 1),它保存实际数据.
后来我使用DBCC Page验证了数据页面的实际内容
DBCC TRACEON(3604)
DBCC PAGE('TestDb',1,298,3)
Run Code Online (Sandbox Code Playgroud)
我看到SQL如何计算m_freecnt字节数 -
= 1007字节RecordSize + 96字节标头+ 2字节偏移= 1105字节
即8K页= 8192字节= 8192 - 1105 = 7087字节自由.
现在我继续在此表中添加记录,以便了解此页面将容纳多少条记录,以及SQL何时会分配一个保留m_FreeCnt的新页面.
(记录大小= 1007和偏移字节= 2)
新增第二条记录 -
Insert into Employee values ('Employee2') GO
Run Code Online (Sandbox Code Playgroud)
最后一个自由计数= 7087,即7087 - 1007 - 2 = 6087 => m_FreeCnt = 6078
Insert into Employee values ('Employee3') GO
Run Code Online (Sandbox Code Playgroud)
最后一个自由计数= 6078,即6078 - 1007 - 2 = 5069 => m_FreeCnt = 5069
Insert into Employee values ('Employee4') GO
Run Code Online (Sandbox Code Playgroud)
最后一个自由计数= 5069即5069 - 1007 - 2 = 4060 => m_FreeCnt = 4060
Insert into Employee values ('Employee5') GO
Run Code Online (Sandbox Code Playgroud)
最后一个自由计数= 4060,即4060 - 1007 - 2 = 3051 => m_FreeCnt = 3051
Insert into Employee values ('Employee6') GO
Run Code Online (Sandbox Code Playgroud)
最后一个自由计数= 3051,即3051 - 1007 - 2 = 2042 => m_FreeCnt = 2042
Insert into Employee values ('Employee7') GO
Run Code Online (Sandbox Code Playgroud)
最后一个自由计数= 2042,即2042 - 1007 - 2 = 1033 => m_FreeCnt = 1033
直到现在一切正常.现在我们在此数据页面中剩下1033个字节.一旦我添加第8条记录,理想情况下它不应该创建另一页,因为可用的字节数是1033字节,这足以容纳第8条记录(1009字节就足够了).但是,SQL会创建一个新的"日期"页面来保存此第8条记录.
我插入第8条记录并运行DBCC IND来检查 -
Insert into Employee values ('Employee7') GO
DBCC IND('TestDb','dbo.Employee',-1)
Run Code Online (Sandbox Code Playgroud)
现在它已经创建了一个PageNumber = 300的新数据页面.
我不明白这一部分.SQL是否保留了一些保留的字节,除了[header(96)+ Data part + offset per page 2 bytes]这个?
您可以尝试运行以上查询并让我知道如果我在这里错过任何东西?或者我们是否应该不关心SQL的这些内存细节?
谢谢.
小智 2
只需重新表述另一个答案即可明确:
一旦您达到页面填充的 81%,该页面的 PFS 记录将把前 2 位更改为11,这意味着“页面已满 95%”并且 SQL 将即使有足够的空间(超过 5% 可用),也不允许插入更多记录。
有两种方法可以解决这个问题:
简单:创建聚集索引 - 然后您可以根据需要将填充因子设置为 100%。
困难:如果页面上的可用空间超过 19%,则可以使用 ONEINSERT语句插入多条记录以 100% 填充页面。
参见示例:
CREATE TABLE TestTable(F0 SMALLINT);
GO
INSERT INTO TestTable (F0)
SELECT TOP 699 1 FROM sys.messages;
GO
BEGIN TRAN
INSERT INTO TestTable (F0)
SELECT TOP 37 2 FROM sys.messages;
SELECT
(SELECT COUNT(*) FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('TestTable'), NULL, NULL, 'DETAILED') WHERE Page_type = 1) AS Pages,
(SELECT COUNT(*) FROM TestTable) AS "Count";
ROLLBACK
GO
BEGIN TRAN
INSERT INTO TestTable (F0) VALUES (3)
GO 2
SELECT
(SELECT COUNT(*) FROM sys.dm_db_database_page_allocations(DB_ID(), OBJECT_ID('TestTable'), NULL, NULL, 'DETAILED') WHERE Page_type = 1) AS Pages,
(SELECT COUNT(*) FROM TestTable) AS "Count";
ROLLBACK
GO
DROP TABLE TestTable
GO
Run Code Online (Sandbox Code Playgroud)
达到 699 条记录后,您可以一次插入 37 条新记录,如果逐条记录插入,则只能插入一条记录。
| 归档时间: |
|
| 查看次数: |
536 次 |
| 最近记录: |