我需要从数据库中整理事务数据,仅保留主数据。从历史上看,这是通过SP以特定顺序从表中删除来完成的,但是由于数据库大小达到半terrabyte,所以速度太慢。
因此,我想到了删除键,截断表和恢复键的想法,并且在大多数情况下,这种方法很奏效,但我发现了一个错误,无法解决。
问题是,具有删除级联的外键将恢复,但没有删除级联,这给应用程序带来了问题,并使我的进程不可用:(
任何人都可以看到缺少的功能吗?还是我在这里可能还会想念的其他东西?
SET NOCOUNT ON
create table #fixes
(TableName nvarchar(200)
,Fix nvarchar(max)
,[type] nvarchar(10))
Insert into #fixes
Select KCU1.TABLE_SCHEMA COLLATE DATABASE_DEFAULT + '.' + KCU1.TABLE_NAME COLLATE DATABASE_DEFAULT
,
'
IF (OBJECT_ID(''' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL) OR (OBJECT_ID(''DSDBA.' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL)
BEGIN
ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA)
+ '.' + QUOTENAME(KCU1.TABLE_NAME)
+ ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) +
'END;
'
,'DROP'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE ORDINAL_POSITION=1
Insert into #fixes
Select
cs.name COLLATE DATABASE_DEFAULT + '.' + ct.name COLLATE DATABASE_DEFAULT
,
'
IF (OBJECT_ID(''' + fk.NAME + ''', ''F'') IS NULL) OR (OBJECT_ID(''DSDBA.' + fk.name + ''', ''F'') IS NULL)
BEGIN
ALTER TABLE '
+ QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name)
+ ' ADD CONSTRAINT ' + QUOTENAME(fk.name)
+ ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
+ ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
+ '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
-- get all the referenced columns
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ')
END
;'
, 'ADD'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs
ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs
ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0
DECLARE @drops VARCHAR(max)
SELECT @drops = COALESCE(@drops + ' ', '') + Fix
FROM #fixes f
where [type] = 'DROP'
DECLARE @adds VARCHAR(max)
SELECT @adds = COALESCE(@adds + ' ', '') + Fix
FROM #fixes f
where [type] = 'ADD'
exec (@drops)
RAISERROR( 'Completed Dropping Keys',0,1) WITH NOWAIT
exec [DSDBA].[usp_utl_TruncateAllTransactions]
RAISERROR( 'Completed Truncating Tables',0,1) WITH NOWAIT
exec (@adds)
RAISERROR( 'Completed Reinstating Keys',0,1) WITH NOWAIT
drop table #fixes
谢谢, D
答案 0 :(得分:0)
所以问题是我只需要处理sys.foreign_keys上的标志。出于我的目的,我们仅使用删除级联,但是为了其他发现这篇文章的人的利益,我包括了其他删除和更新操作的处理
SET NOCOUNT ON
create table #fixes
(TableName nvarchar(200)
,Fix nvarchar(max)
,[type] nvarchar(10))
Insert into #fixes
Select KCU1.TABLE_SCHEMA COLLATE DATABASE_DEFAULT + '.' + KCU1.TABLE_NAME COLLATE DATABASE_DEFAULT
,
'
IF (OBJECT_ID(''' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL) OR (OBJECT_ID(''DSDBA.' + rc.CONSTRAINT_NAME + ''', ''F'') IS NOT NULL)
BEGIN
ALTER TABLE ' + QUOTENAME(RC.CONSTRAINT_SCHEMA)
+ '.' + QUOTENAME(KCU1.TABLE_NAME)
+ ' DROP CONSTRAINT ' + QUOTENAME(rc.CONSTRAINT_NAME) +
'END;
'
,'DROP'
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
WHERE ORDINAL_POSITION=1
Insert into #fixes
Select
cs.name COLLATE DATABASE_DEFAULT + '.' + ct.name COLLATE DATABASE_DEFAULT
,
'
IF (OBJECT_ID(''' + fk.NAME + ''', ''F'') IS NULL) OR (OBJECT_ID(''DSDBA.' + fk.name + ''', ''F'') IS NULL)
BEGIN
ALTER TABLE '
+ QUOTENAME(cs.name) + '.' + QUOTENAME(ct.name)
+ ' ADD CONSTRAINT ' + QUOTENAME(fk.name)
+ ' FOREIGN KEY (' + STUFF((SELECT ',' + QUOTENAME(c.name)
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.parent_column_id = c.column_id
AND fkc.parent_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'')
+ ') REFERENCES ' + QUOTENAME(rs.name) + '.' + QUOTENAME(rt.name)
+ '(' + STUFF((SELECT ',' + QUOTENAME(c.name)
-- get all the referenced columns
FROM sys.columns AS c
INNER JOIN sys.foreign_key_columns AS fkc
ON fkc.referenced_column_id = c.column_id
AND fkc.referenced_object_id = c.[object_id]
WHERE fkc.constraint_object_id = fk.[object_id]
ORDER BY fkc.constraint_column_id
FOR XML PATH(N''), TYPE).value(N'.[1]', N'nvarchar(max)'), 1, 1, N'') + ')
'
/** BEGIN SOLUTION **//
+
case objectproperty(fk.object_id, 'CnstDeleteAction') when 0 then '' when 1 then 'ON DELETE CASCADE' when 2 then 'ON DELETE SET NULL' when 3 then 'ON DELETE SET DEFAULT' end
+
case objectproperty(fk.object_id, 'CnstUpdateAction') when 0 then '' when 1 then 'ON UPDATE CASCADE' when 2 then 'ON UPDATE SET NULL' when 3 then 'ON UPDATE SET NULL' end
+
/** END SOLUTION **//
'
END
;'
, 'ADD'
FROM sys.foreign_keys AS fk
INNER JOIN sys.tables AS rt -- referenced table
ON fk.referenced_object_id = rt.[object_id]
INNER JOIN sys.schemas AS rs
ON rt.[schema_id] = rs.[schema_id]
INNER JOIN sys.tables AS ct -- constraint table
ON fk.parent_object_id = ct.[object_id]
INNER JOIN sys.schemas AS cs
ON ct.[schema_id] = cs.[schema_id]
WHERE rt.is_ms_shipped = 0 AND ct.is_ms_shipped = 0
DECLARE @drops VARCHAR(max)
SELECT @drops = COALESCE(@drops + ' ', '') + Fix
FROM #fixes f
where [type] = 'DROP'
DECLARE @adds VARCHAR(max)
SELECT @adds = COALESCE(@adds + ' ', '') + Fix
FROM #fixes f
where [type] = 'ADD'
Select * from #fixes
--drop table #fixes