通过添加列PartitionID,将包含> 2亿条记录的SQL Server表划分为~100个分区(不是真正的SQL Server分区 - 它不在SQL Server的兼容版本上运行)。 PartitionID是表的聚集索引定义的前半部分;另一半是唯一的自动递增整数ID。 PartitionID也是Partition表中的外键。在不知道PartitionID的情况下,不会访问Example中的记录;它们通常在与单个PartitionID(或少量PartitionID)相关联的范围内访问。
CREATE TABLE Example (
ID BIGINT IDENTITY(1, 1) NOT NULL,
PartitionID DECIMAL(18, 0) NOT NULL,
-- Other columns omitted for brevity
CONSTRAINT PK_Example PRIMARY KEY NONCLUSTERED (ID),
CONSTRAINT FK_Example_Partition FOREIGN KEY (PartitionID) REFERENCES Partition (ID)
)
CREATE UNIQUE CLUSTERED INDEX IX_Example ON Example(PartitionID, ID)
分区行无限期保留,但通常通过对具有相同PartitionID的范围发出DELETE语句来清除示例行。随着时间的推移,这会导致未被任何Example行引用的分区行。这不是问题;问题是确定仍然引用 的分区行。
如果不采用用户级管理技术,例如在分区表中添加和手动维护ReferenceCount字段,或添加并手动维护正在使用的PartitionID列表,我们可以使用系统级技术来发现一组仍在使用的PartitionID - 没有扫描表中的所有行示例?
SELECT DISTINCT PartitionID FROM Example
上述查询需要几十秒才能返回100个值,因为它扫描了聚集索引中数百万行的100个。仅在PartionID上添加另一个非常窄的索引可能会减少I / O并将时间减半,但实际上SQL Server仍在扫描该索引。
CREATE NONCLUSTERED INDEX IX_Example_PartitionID ON Example(PartitionID)
我应该避免加入Partition with Example(执行一些聚簇索引搜索而不是索引扫描),因为随着时间的推移,搜索次数会增加(并降低性能)。
SELECT DISTINCT PartitionID FROM Partition p WHERE EXISTS (
SELECT TOP 1 1 FROM Example e WHERE p.ID = e.PartitionID
)