Comment puis-je nettoyer la SSISDB?

quand j'ai installé ceci, j'ai oublié la période de rétention. Ma base de données est devenue assez grande donc je veux diminuer sa taille. Si je change simplement la période de conservation (elle était de 365), cela cause des problèmes avec SSIS qui exécute mes paquets. Je l'ai même modifié par petits incréments, mais la suppression créerait des serrures qui empêcheraient de nouveaux emplois de fonctionner.

avez-vous des idées pour contourner cela? J'ai pensé à créer une nouvelle SSISDB.

21
demandé sur Paul Riker 2014-02-14 17:58:10

2 réponses

Phil Brammer a rencontré ceci et une foule d'autres choses liées au soin et à l'alimentation du catalogue SSIS, qu'il couvre sur son post Catalogue D'Indexation Des Recommandations.

problème de Racine

le problème fondamental est que MS a essayé de concevoir les SSI avec RI à l'esprit, mais ils étaient paresseux et ont permis aux deletes en cascade de se produire plutôt que de les traiter explicitement.

Hors de la boîte, la nouvelle SSIS 2012 catalogue de la base de données (SSISDB) a une indexation de base appliquée, avec intégrité référentielle définie pour faire des suppressions en cascade entre la plupart des tables.

entrer le travail D'Agent SQL, " SSIS Server Maintenance Job."Cette tâche par défaut est définie pour fonctionner à minuit tous les jours, et utilise deux paramètres de catalogue pour fonctionner: "nettoyer les journaux périodiquement" et "période de rétention (jours)."Lorsqu'elles sont définies, la tâche de maintenance élimine toutes les données en dehors de la période de conservation indiquée.

Ce travail d'entretien supprime, 10 enregistrements à un moment donné dans une boucle, de l'interne.les opérations et puis cascade dans de nombreuses tables en aval. Dans notre cas, nous avons environ 3000 enregistrements d'opérations à supprimer tous les jours (10 à la fois!) qui se traduit en 1,6 millions de lignes à partir de l'interne.operation_messages. C'est juste une table en aval! Tout ce processus bloque complètement la base de données SSISDB de toutes les données SELECT/INSERT

Résolution

Jusqu'à ce que MS change la façon dont les choses fonctionnent, le l'option est

déplacer le calendrier des travaux de maintenance à un moment plus approprié pour votre environnement

je sais qu'à mon client actuel, nous ne chargeons des données que pendant les petites heures, donc la SSISDB est silencieuse pendant les heures de bureau.

si exécuter le travail d'entretien pendant une période calme n'est pas une option, alors vous envisagez d'élaborer vos propres instructions de suppression pour essayer d'obtenir les suppressions en cascade à sucer moins.

À mon client actuel, nous avons exécuté environ 200 paquets chaque nuit au cours des 10 derniers mois et sommes également à 365 jours de l'histoire. Nos plus grandes tables, par un ordre de grandeur.

Schema    Table                   RowCount
internal  event_message_context   1,869,028
internal  operation_messages      1,500,811
internal  event_messages          1,500,803

le pilote de toutes ces données,internal.operations ne contient que 3300 lignes, ce qui correspond au commentaire de Phil sur la croissance exponentielle de ces données.

alors, identifiez le operation_id pour être vidé et la suppression de la feuille de tables de travail, revenir à la base, internal.operations tableau.

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;

les mises en garde habituelles s'appliquent - ne faites pas confiance au code de randoms sur internet - utiliser les diagrammes des tables ssistalk et/ou system pour identifier toutes les dépendances - vous pourriez avoir besoin de segmenter seulement vos opérations de suppression dans des opérations plus petites - vous pourriez bénéficier en laissant tomber RI pour les opérations, mais être certain de les réactiver avec l'option check afin qu'ils soient fiables. - consulter votre dba si les opérations durent plus de 4 heures

Références

31
répondu billinkc 2016-02-04 15:24:49

j'ai créé une procédure stockée similaire pour faire l'archivage qui est ci-dessous. Laissez-moi savoir si tout les bugs. Je n'offre aucune garantie, mais ça marche très bien pour moi. Ce code n'est en aucun cas poli, mais je voulais le partager (c'est-à-dire que l'utilisation de la table temp ne peut être exécutée qu'une fois à la fois, peut-être qu'une table scoped de session serait mieux)

j'ai eu un problème où par la procédure propre DE MS soufflait sur le fichier LDF et verrouillait les tables pendant de longues périodes, et une fois causé le serveur à exécuter de l'espace. J'ai décidé d'écrire mon propre pour supprimer les grandes tables en premier et ensuite supprimer la table d'opération. Cette procédure ci-dessous n'utilise jamais plus de 1 GO dans l'espace log, et ne verrouille pas les tables pendant de très longues périodes, ce qui est une capture 22 lorsque les tâches SSIS doivent fonctionner toute la journée.

d'Abord il se connecte à une table

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

et utilise une table temporaire

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

voici la procédure

    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
1
répondu Ab Bennett 2018-05-16 00:01:00