InDeF 21.5, C# .NET 4.x, MS SQL Server.
Una delle nostre elaborazioni si basa su una decina di tabelle DB di appoggio, il cui contenuto viene mantenuto fintantoché non viene lanciata una nuova elaborazione. Al lancio della nuova elaborazione, tutti i record di appoggio vengono eliminati per poi procedere all’inserimento dei nuovi. La stessa elaborazione può essere lanciata da più utenti con parametri diversi, per cui le tabelle contengono i dati di appoggio di diverse sessioni di elaborazione.
Alcune di queste tabelle contengono oltre un milione di record, e la singola elaborazione è formata da oltre cento mila record.
Randomicamente, la cancellazione dei dati di appoggio di una singola elaborazione va in timeout.
Nello specifico, una semplice
DELETE FROM [tabella] WHERE IdElaborazione=[valore_id]
sfora i 30 secondi standard e SQL Server genera l’errore di timeout (IdElaborazione è indicizzato).
Cercando tra le varie soluzioni, abbiamo scelto l’idea di frammentare la cancellazione in bocconi più piccoli, evitando di strozzare SQL Server, lasciandogli nel contempo la gestione dell’intero processo di eliminazione.
In pratica, generiamo al volo uno script, per poi eseguirlo tramite SQLExecute:
BEGIN TRANSACTION;
WHILE EXISTS (SELECT TOP 1 * FROM |1 |2)
BEGIN
WITH LT AS
(
SELECT TOP 60000 *
FROM |1 |2
)
DELETE FROM LT
END;
COMMIT;
Dove |1 è il nome della tabella e |2 l’eventuale clausola where.
Nei test effettuati, dove prima una singola delete durava più di 30 secondi, ora l’eliminazione dei record di 10 tabelle (215mila record in totale su oltre 2milioni) impiega poco più di 60 secondi, senza dare timeout.
Avremmo potuto eseguire direttamente da InDe diverse delete, ma avremmo in pratica allungato il timeout complessivo per l’intera tabella e sollecitato il driver rischiando di ingolfarlo. Con la soluzione proposta invece il numero di istruzioni (e quindi timeout) eseguite da SQL Sever non è cambiato.
Le parti dolenti sono due:
- Se dovessimo cambiare motore DB?.
- Il nome della tabella è dato da una costante, totalmente slegato dallo schema db all’interno del progetto.
Voi che soluzioni avete adottato?