2010-04-30 7 views
1

Voici mon scénario: nous avons une base de données, appelons-la Logging, avec une table qui contient des enregistrements de Log4Net (via MSMQ). Le mode de récupération de la base de données est défini sur Simple: les journaux de transactions ne nous intéressent pas: ils peuvent être reconduits.Sql Server: les suppressions de segment remplissent toujours le journal des transactions; en cas d'échec, toutes les suppressions sont annulées - pourquoi?

Nous avons un travail qui utilise des données de sp_spaceused pour déterminer si nous avons atteint un certain seuil de taille. Si le seuil est dépassé, nous déterminons combien de lignes doivent être supprimées pour ramener la taille à x% de ce seuil. (En aparté, j'utilise exec sp_spaceused MyLogTable, TRUE pour obtenir le nombre de lignes et une approximation grossière de leur taille moyenne, même si je ne suis pas convaincu que ce soit la meilleure façon d'y arriver, mais c'est un problème différent.)

J'essaie ensuite de morceau supprime (disons, 5000 à la fois) en bouclant un appel à une procédure stockée qui fait essentiellement ceci:

DELETE TOP (@RowsToDelete) FROM [dbo].[MyLogTable] 

jusqu'à ce que j'ai supprimé ce qui doit être supprimé.

Voici le problème: Si j'ai beaucoup de lignes à supprimer, le fichier du journal des transactions se remplit. Je peux le regarder grandir en exécutant

dbcc sqlperf (logspace) 

Ce qui me déconcerte est que, lorsque le travail échoue, toutes les lignes supprimées se révulsés. En d'autres termes, il semble que tous les morceaux soient enveloppés (en quelque sorte) dans une transaction implicite.

J'ai essayé explicitement de désactiver les transactions implicites, en encapsulant chaque instruction DELETE dans un BEGIN et un COMMIT TRAN, mais en vain: tous les blocs supprimés réussissent, ou pas du tout.

Je sais que la réponse est simple, faites en sorte que votre fichier journal soit assez grand pour gérer le plus grand nombre possible d'enregistrements que vous ayez jamais supprimés, mais pourquoi est-ce traité comme une seule transaction?

Désolé si j'ai manqué quelque chose de facile, mais j'ai regardé beaucoup de messages concernant la croissance du fichier journal, les modes de récupération, etc., et je ne peux pas comprendre cela.

Une autre chose: une fois que le travail a échoué, le fichier journal reste à environ 95 - 100% plein pendant un certain temps avant de retomber. Cependant, si j'exécute

checkpoint 
dbcc dropcleanbuffers 

il redescend à environ 5% d'utilisation.

TIA.

Répondre

0

Le fichier journal dans le modèle de récupération simple est automatiquement tronqué à chaque point de contrôle. Vous pouvez invoquer le point de contrôle manuellement comme vous le faites à la fin de la boucle, mais vous pouvez également le faire à chaque itération. La fréquence des points de contrôle est déterminée automatiquement par le serveur SQL en fonction du paramètre d'intervalle de récupération.

Dans la mesure où les 'toutes les suppressions sont annulées', je ne vois pas d'autre explication qu'une transaction externe. Pouvez-vous poster du code entier qui nettoie le journal? Comment invoquez-vous ce code? Quel est votre paramètre de transactions implicites? Hm .. Si le journal se développe et ne tronque pas automatiquement, cela peut également indiquer qu'une transaction est en cours en dehors de la boucle. Pouvez-vous select @@trancount avant votre boucle et peut-être à chaque itération pour savoir ce qui se passe?

+1

Piotr, merci pour votre suggestion s. En fait, j'ai exécuté un sproc "pilote" à partir de Query Analyzer. Votre question à propos d'une transaction externe me fait me demander, Est-ce que Query Analyzer a activé implicit_transactions par défaut? J'ai vérifié Profilier et je n'ai pas vu ça. Cependant, je vais réessayer avec SET IMPLICIT_TRANSACTIONS OFF dans ma session Query Analyzer et voir si cela fait une différence (que tout ou partie soit annulé en cas d'échec). Je vais republier quand j'ai effectué ce test. Merci, Paul –

0

Eh bien, j'ai essayé plusieurs choses, mais toutes les suppressions sont annulées. J'ai ajouté printint @@TRANCOUNT à la fois avant et après la suppression et je reçois zéro comme le nombre. Pourtant, en cas d'échec, toutes les suppressions sont annulées ... J'ai ajouté SET IMPLICIT_TRANSACTIONS OFF à plusieurs endroits (y compris dans mon appel initial à partir de Query Analyzer, mais cela ne semble pas utile.) C'est le corps de la procédure stockée qui est appelée (j'ai mis @RowsToDelete-5000 et 8000):

SET NOCOUNT ON; 
    print N'@@TRANCOUNT PRIOR TO DELETE: ' + CAST(@@TRANCOUNT AS VARCHAR(20)); 

    set implicit_transactions off; 
    WITH RemoveRows AS 
    (
    SELECT ROW_NUMBER() OVER(ORDER BY [Date] ASC) AS RowNum 
    FROM [dbo].[Log4Net] 
) 

    DELETE FROM RemoveRows 
    WHERE RowNum < @RowsToDelete + 1 

    print N'@@TRANCOUNT AFTER DELETE: ' + CAST(@@TRANCOUNT AS VARCHAR(20)); 

Il est appelé à partir de ce t-sql.

WHILE @RowsDeleted < @RowsToDelete 
BEGIN 
EXEC [dbo].[DeleteFromLog4Net] @RowsToDelete 
SET @RowsDeleted = @RowsDeleted + @RowsToDelete 
Set @loops = @loops + 1 
print 'Loop: ' + cast(@loops as varchar(10)) 
END 

Je dois admettre que je suis perplexe, je ne suis pas un gourou de DB, mais Je pensais avoir compris assez pour comprendre cela ....

+0

Eh bien, je déteste vraiment admettre cela, mais dans '@ RowsToDelete' je passais par le nombre total de lignes à supprimer - pas ma taille de bloc. Soupir. Un peu plus de déclarations d'impression et un autre ensemble d'yeux a attrapé mon erreur .... Problème résolu. –

Questions connexes