能,但需表已分区、归档表结构完全一致且边界对齐;SWITCH仅修改元数据指针,不移动数据,故远快于DELETE。

能,但前提是表已分区、归档表结构完全一致、且边界对齐——否则ALTER TABLE ... SWITCH PARTITION直接报错,不是慢,是根本执行不了。
为什么SWITCH比DELETE快得多
它不碰数据页,只改系统表里的元数据指针:把某个分区的“归属权”从原表瞬间转给另一个空表。几百万行切换耗时通常低于100ms,日志写入几乎可忽略;而DELETE要逐行加锁、记日志、触发索引维护,TB级删历史数据可能卡住业务十几分钟。
- 必须在同一个数据库、同一文件组下操作(跨文件组会报错 Msg 4950)
- 目标表不能是临时表、不能有外键引用、不能启用
ALLOW_SNAPSHOT_ISOLATION - 如果原表有
IDENTITY列,目标表也得允许SET IDENTITY_INSERT ON(但通常归档表不该有该列)
归档表建错一个字段就失败:五项必须脚本化校验
肉眼比DDL不可靠,SWITCH失败最常见原因是结构不一致,报错如Msg 4926或ORA-14097(金仓兼容版)。必须用查询确认以下五点:
- 列名、顺序、类型、长度、精度、是否允许NULL——全部严格一致(比如
varchar(50)vsvarchar(100)就不行) - 所有索引:列顺序、ASC/DESC、包含列、过滤条件(SQL Server)、填充因子、数据压缩选项
- 约束:源表不能有任何
CHECK或DEFAULT约束(哪怕值一样也不行) - 主键/唯一键:必须同名、同列、同属性(比如都是
NOT NULL) - 统计信息:切换后原表统计不会自动更新,需手动跑
UPDATE STATISTICS,否则后续查询计划可能劣化
分区函数边界写错会导致数据错位
按时间归档时,若分区函数用RANGE RIGHT,但切割点设成'2024-01-01',那实际归入该分区的是>= '2024-01-01'的数据——你本想切走2023年全量,结果切走了2024年及以后。务必用这两条语句核对:
SELECT $PARTITION.pf_DateRange(CreatedDate) AS partition_number, COUNT(*) FROM dbo.LogTable GROUP BY $PARTITION.pf_DateRange(CreatedDate)
SELECT destination_id, filegroup_name FROM sys.partition_schemes ps JOIN sys.destination_data_spaces dds ON ps.data_space_id = dds.partition_scheme_id JOIN sys.filegroups fg ON dds.data_space_id = fg.data_space_id WHERE ps.name = 'ps_DateRange'
再结合sys.partition_range_values确认每个边界值对应哪一分区编号。
典型三步不能少:建表 → 切换 → 清理
不能跳过中间表直接删分区——SQL Server 不支持DROP PARTITION。标准链路是:
- 先建归档表:
CREATE TABLE dbo.LogTable_Archive_2023 (...) ON [FG_ARCHIVE_2023],含相同聚集索引、无约束、空表 - 执行切换:
ALTER TABLE dbo.LogTable SWITCH PARTITION 1 TO dbo.LogTable_Archive_2023(原子操作,失败则全回滚) - 后续处理:立即
DROP TABLE释放空间,或BACKUP归档,或TRUNCATE后复用——但别留着,它会持续占用文件组空间
最容易被忽略的是:切换后原表的执行计划可能因统计信息陈旧而变差,尤其当刚切走大量历史数据、剩余数据分布发生偏移时,UPDATE STATISTICS这一步不能省。











