当我设置时,我忽略了保留期。我的数据库变得非常大,所以我希望减小它的大小。如果我只是更改保留期(它是365),则会导致SSIS运行我的包时出现问题。我甚至以小增量更改了它,但删除语句会创建阻止新作业运行的锁。
任何想法如何解决这个问题?我考虑过只创建一个新的SSISDB。
答案 0 :(得分:34)
根本问题是MS试图设计带有RI的SSIS,但它们是懒惰的,允许级联删除发生而不是显式处理它们。
开箱即用,新的SSIS 2012目录数据库(SSISDB)应用了一些基本索引,并将参照完整性设置为在大多数表之间进行级联删除。
输入SQL代理作业“SSIS服务器维护作业”。默认情况下,此作业设置为每天午夜运行,并使用两个目录参数来运行:“定期清理日志”和“保留期(天)”。设置完成后,维护作业将清除指定保留期之外的所有数据。
此维护作业从内部操作中一次删除循环中的10条记录,然后级联到下游的多个表中。在我们的例子中,我们每天有大约3000个操作记录要删除(一次10个!),从internal.operation_messages转换为160万行。那只是一张下游桌子!整个过程完全完全锁定了SSISDB数据库中的任何SELECT / INSERT数据
在MS改变工作原理之前,支持的选项是
将维护作业计划移至适合您环境的更合适的时间
我知道在我目前的客户端,我们只在凌晨加载数据,因此SSISDB在营业时间内保持安静。
如果在安静期间运行维护作业不是一个选项,那么您正在考虑制作自己的删除语句,以尝试将级联删除添加到 suck less 。
在我目前的客户中,我们在过去10个月内每晚运行约200个套餐,并且还有365天的历史。我们最大的表格是一个数量级的。
Schema Table RowCount
internal event_message_context 1,869,028
internal operation_messages 1,500,811
internal event_messages 1,500,803
所有这些数据的驱动程序internal.operations
中只有3300行,这与Phil关于这些数据呈指数增长的评论一致。
因此,确定要清除的operation_id
以及从叶表中删除工作回到核心internal.operations
表。
USE SSISDB;
SET NOCOUNT ON;
IF object_id('tempdb..#DELETE_CANDIDATES') IS NOT NULL
BEGIN
DROP TABLE #DELETE_CANDIDATES;
END;
CREATE TABLE #DELETE_CANDIDATES
(
operation_id bigint NOT NULL PRIMARY KEY
);
DECLARE @DaysRetention int = 100;
INSERT INTO
#DELETE_CANDIDATES
(
operation_id
)
SELECT
IO.operation_id
FROM
internal.operations AS IO
WHERE
IO.start_time < DATEADD(day, -@DaysRetention, CURRENT_TIMESTAMP);
DELETE T
FROM
internal.event_message_context AS T
INNER JOIN
#DELETE_CANDIDATES AS DC
ON DC.operation_id = T.operation_id;
DELETE T
FROM
internal.event_messages AS T
INNER JOIN
#DELETE_CANDIDATES AS DC
ON DC.operation_id = T.operation_id;
DELETE T
FROM
internal.operation_messages AS T
INNER JOIN
#DELETE_CANDIDATES AS DC
ON DC.operation_id = T.operation_id;
-- etc
-- Finally, remove the entry from operations
DELETE T
FROM
internal.operations AS T
INNER JOIN
#DELETE_CANDIDATES AS DC
ON DC.operation_id = T.operation_id;
通常的警告适用 - 不要相信互联网上的randoms代码 - 使用ssistalk和/或系统表中的图表来识别所有依赖项 - 您可能只需要将删除操作分成较小的操作 - 您可以通过删除RI进行操作而受益,但一定要使用check选项重新启用它们,以便它们受信任。 - 如果操作持续时间超过4小时,请咨询您的dba
答案 1 :(得分:1)
我创建了一个类似的存储过程来进行下面的归档。如果有任何错误,请告诉我。我不提供任何保证,但它对我来说很好。这段代码绝不是完美的,但我想分享(即使用临时表意味着一次只能运行一次,也许会话范围表会更好)
我遇到了一个问题,MS自己的清理程序会破坏LDF文件并长时间锁定表,并导致服务器空间不足。我决定先自己编写删除较大的表,然后删除操作表。下面的这个过程在日志空间中从不使用超过1GB的空间,并且在SSIS作业必须全天运行时,不会长时间锁定表,这是一个问题22。
首先它记录到表
CREATE TABLE [dbo].[ETL_SSIS_Operations_Archived](
[id] [int] IDENTITY(1,1) NOT NULL,
[operation_id_str] [varchar](900) NOT NULL,
[event_messages_context] [int] NULL,
[event_messages] [int] NULL,
[operation_messages] [int] NULL,
[num_operators] [int] NULL,
[chunksize] [int] NULL,
[DateStarted] [datetime] NOT NULL,
[DateFinished] [datetime] NULL,
[executionSecs] [int] NULL,
[DelOperationsDateStarted] [datetime] NULL,
[DelOperationsDateFinished] [datetime] NULL,
[DelOperationsExecutionSecs] [int] NULL
) ON [PRIMARY]
GO
并使用临时表
CREATE TABLE [dbo].[tmp_etl_operations_id](
[operation_id] [int] NULL,
[dateCreated] [datetime] NULL default getdate()
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tmp_etl_operations_id] ADD DEFAULT (getdate()) FOR [dateCreated]
GO
这是程序
CREATE PROCEDURE [dbo].[sp_Archive_SSIDB_Catalogue]
AS
BEGIN
DECLARE @MyCursor as CURSOR;
DECLARE @l_operation_id int;
declare @l_rows_del int = 1
declare @l_operation_id_str varchar(8000) = ''
declare @l_id int
declare @l_event_message_context int = 0
declare @l_event_messages int = 0
declare @l_operation_messages int = 0
declare @l_loop_num int = 1
declare @C_BULK_NUM int = 100
declare @C_CHUNK_SIZE int = 100000
declare @l_last_rec char(1)
SET @MyCursor = CURSOR FOR
with params as
(
-- i round up the midnight that day, just so i know once it is done for the day it is done
-- and if the real maintenance job was to run after this (just for the sake of it to double ensure nothing has been missed), but not actually need to do
-- anything as its already done in here, no new operations would have snuck in due to the sliding system time
SELECT cast(dateadd(day,1,GETDATE() - CONVERT(int,property_value)) as date) ArchiveDate
FROM ssisdb.[catalog].[catalog_properties]
WHERE property_name = 'RETENTION_WINDOW'
)
select operation_id,iif(r=c,'Y','N') lastrec
from
(
select operation_id,row_number() over (partition by null order by operation_id) r,count(*) over (partition by null) c
FROM ssisdb.[internal].[operations]
WHERE ( [end_time] <= (select ArchiveDate from params)
-- A special case when END_TIME is null, we will delete the records based on the created time
OR ([end_time] IS NULL AND [status] = 1 AND [created_time] <= (select ArchiveDate from params) ))
) x
order by operation_id
OPEN @MyCursor;
FETCH NEXT FROM @MyCursor INTO @l_operation_id,@l_last_rec
WHILE @@FETCH_STATUS = 0
BEGIN
set @l_operation_id_str = @l_operation_id_str+','+cast(@l_operation_id as varchar(100))
if @l_loop_num = 1
begin
delete from tmp_etl_operations_id
set @l_operation_id_str = cast(@l_operation_id as varchar(100))
end
insert into tmp_etl_operations_id (operation_id) select @l_operation_id
if @l_loop_num = @C_BULK_NUM or @l_last_rec='Y'
begin
set @l_loop_num = 1
set @l_event_message_context = 0
set @l_event_messages = 0
set @l_operation_messages = 0
insert into ETL_SSIS_Operations_Archived ([operation_id_str], num_operators,chunksize, event_messages_context, event_messages, operation_messages, datestarted)
select @l_operation_id_str, @C_BULK_NUM,@C_CHUNK_SIZE,@l_event_message_context,@l_event_messages,@l_operation_messages,getdate()
--where 0 = (select count(*) from ETL_SSIS_Operations_Archived where operation_id=@l_operation_id_str)
set @l_id = Scope_Identity()
set @l_rows_del = @C_CHUNK_SIZE
while (@l_rows_del >= @C_CHUNK_SIZE)
begin
delete top (@C_CHUNK_SIZE)
from ssisdb.internal.event_message_context
where operation_id in (select operation_id from etl..tmp_etl_operations_id)
set @l_rows_del = @@ROWCOUNT
set @l_event_message_context = @l_event_message_context+@l_rows_del
update ETL_SSIS_Operations_Archived
set event_messages_context = event_messages_context+@l_rows_del
where id = @l_id--operation_id = @l_operation_id_str
end
set @l_rows_del = @C_CHUNK_SIZE
while (@l_rows_del >= @C_CHUNK_SIZE)
begin
delete top (@C_CHUNK_SIZE)
from ssisdb.internal.event_messages
where operation_id in (select operation_id from tmp_etl_operations_id)
set @l_rows_del = @@ROWCOUNT
set @l_event_messages = @l_event_messages+@l_rows_del
update ETL_SSIS_Operations_Archived
set event_messages = event_messages+@l_rows_del
where id = @l_id--operation_id = @l_operation_id_strwhere operation_id = @l_operation_id_str
end
set @l_rows_del = @C_CHUNK_SIZE
while (@l_rows_del >= @C_CHUNK_SIZE)
begin
delete top (@C_CHUNK_SIZE)
from ssisdb.internal.operation_messages
where operation_id in (select operation_id from tmp_etl_operations_id)
set @l_rows_del = @@ROWCOUNT
set @l_operation_messages = @l_operation_messages+@l_rows_del
update ETL_SSIS_Operations_Archived
set operation_messages = operation_messages+@l_rows_del
where id = @l_id--operation_id = @l_operation_id_strwhere operation_id = @l_operation_id_str --
end
update ETL_SSIS_Operations_Archived
set DateFinished = getdate()
,executionSecs = Datediff(s, DateStarted, getdate())
,DelOperationsDateStarted = getdate()
where id = @l_id--operation_id = @l_operation_id_strwhere operation_id = @l_operation_id_str --
-- lets delete the operations now
delete --top (@C_CHUNK_SIZE)
from ssisdb.internal.operations
where operation_id in (select operation_id from tmp_etl_operations_id)
update ETL_SSIS_Operations_Archived
set DelOperationsDateFinished = getdate()
,DelOperationsExecutionSecs = Datediff(s, DelOperationsDateStarted, getdate())
where id = @l_id--operation_id = @l_operation_id_strwhere operation_id = @l_operation_id_str --
end
else
begin
set @l_loop_num = @l_loop_num+1
end
FETCH NEXT FROM @MyCursor INTO @l_operation_id,@l_last_rec
END
CLOSE @MyCursor;
DEALLOCATE @MyCursor;
END
答案 2 :(得分:0)
已从本文中找到有用的清理脚本:SQL SERVER – Huge Size of SSISDB – Catalog Database SSISDB Cleanup Script
USE SSISDB
GO
DELETE FROM [internal].[executions]
GO
DELETE FROM [internal].[executable_statistics]
GO
DELETE FROM [internal].[execution_component_phases]
GO
DELETE FROM [internal].[execution_data_statistics]
GO
DELETE FROM [internal].[execution_data_taps]
GO
DELETE FROM [internal].[execution_parameter_values]
GO
DELETE FROM [internal].[execution_property_override_values]
GO
DELETE FROM [internal].[extended_operation_info]
GO
DELETE FROM [internal].[operation_messages]
GO
DELETE FROM [internal].[event_messages]
GO
DELETE FROM [internal].[event_message_context]
GO
DELETE FROM [internal].[operation_os_sys_info]
GO
DELETE FROM [internal].[operation_permissions]
GO
DELETE FROM [internal].[validations]
GO
还可以考虑将数据库切换为简单恢复模式,但要为日志文件保留足够的空间。
答案 3 :(得分:-1)
运行此 sproc:
EXEC [internal].[cleanup_server_retention_window]