Answers:
否,SQL Server无法检测到重复的行
SQL Server正在填充分配的页面内的空白页面或部分空白页面。
因此,如果我的行很窄(例如2列),则可以在同一页上添加几百行而不增加使用的空间。
快速而肮脏的演示(没有重复的行,但是您可以根据需要进行操作)
IF OBJECT_ID('dbo.Demo') IS NOT NULL
DROP TABLE dbo.Demo;
GO
CREATE TABLE dbo.Demo (DemoID int NOT NULL IDENTITY(1,1), Demo char(1) NOT NULL)
GO
SELECT 'zero rows, zero space', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
INSERT dbo.Demo VALUES ('a');
GO
SELECT 'one row. Peanuts', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
INSERT dbo.Demo VALUES ('b');
GO 100
SELECT '101 rows. All on one page', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
INSERT dbo.Demo VALUES ('b');
GO 1899
SELECT '2000 rows. More than one page', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
TRUNCATE TABLE dbo.Demo
GO
SELECT 'zero rows, zero space. TRUNCATE deallocates pages', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
INSERT dbo.Demo VALUES ('c');
GO 500
SELECT '500 rows. Some space used', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
DELETE dbo.Demo
GO
SELECT 'zero rows after delete. Space still allocated', SUM(ps.reserved_page_count)/128.0 AS ReservedMB, SUM(ps.used_page_count)/128.0 AS UsedMB
FROM sys.dm_db_partition_stats ps
WHERE ps.object_id = OBJECT_ID('dbo.Demo')
GO
IF OBJECT_ID('dbo.Demo') IS NOT NULL
DROP TABLE dbo.Demo;
GO
SQL Server是否使用指针而不是存储重复的行?
它取决于SQL Server的版本和数据压缩选项:
前缀压缩 [...]列中的重复前缀值被对相应前缀的引用替换。
字典压缩完成前缀压缩后,将应用字典压缩。字典压缩在页面上的任何位置搜索重复的值,并将其存储在CI区域中。与前缀压缩不同,字典压缩不限于一列。字典压缩可以替换页面上任何地方出现的重复值。下图显示了字典压缩后的同一页面。
因此,对于前缀和字典压缩(页面压缩),SQL Server使用指针在同一列或差异内存储 (部分或全部)重复的值(不重复的行)。列。
CREATE DATABASE TestComp;
GO
USE TestComp;
GO
CREATE TABLE Person1 (
PersonID INT IDENTITY PRIMARY KEY,
FirstName NVARCHAR(100) NOT NULL,
LastName NVARCHAR(100) NOT NULL
);
GO
DECLARE
@f NVARCHAR(100) = REPLICATE('A',100),
@l NVARCHAR(100) = REPLICATE('B',100);
INSERT Person1 (FirstName, LastName)
VALUES (@f, @l);
GO 1000
CREATE TABLE Person2 (
PersonID INT IDENTITY PRIMARY KEY,
FirstName NVARCHAR(100) NOT NULL,
LastName NVARCHAR(100) NOT NULL
);
GO
ALTER TABLE Person2
REBUILD
WITH (DATA_COMPRESSION=PAGE);
GO
DECLARE
@f NVARCHAR(100) = REPLICATE('A',100),
@l NVARCHAR(100) = REPLICATE('B',100);
INSERT Person2 (FirstName, LastName)
VALUES (@f, @l);
GO 1000
SELECT f.page_count AS PageCount_Person1_Uncompressed
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('Person1'), 1, DEFAULT, DEFAULT) f
SELECT f.page_count AS PageCount_Person2_Compressed
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID('Person2'), 1, DEFAULT, DEFAULT) f
GO
结果:
PageCount_Person1_Uncompressed
------------------------------
53
PageCount_Person2_Compressed
----------------------------
2