it-swarm.com.de

Wie lösche ich große Daten einer Tabelle in SQL ohne Protokoll?

Ich habe eine große Datentabelle ..__ In dieser Tabelle befinden sich 10 Millionen Datensätze.

Was ist der beste Weg für diese Abfrage?

   Delete LargeTable where readTime < dateadd(MONTH,-7,GETDATE())
89
user3107343
  1. Wenn Sie alle Zeilen in dieser Tabelle löschen, besteht die einfachste Option darin, die Tabelle abzuschneiden 

    TRUNCATE TABLE LargeTable
    GO
    

    Beim Abschneiden der Tabelle wird die Tabelle einfach geleert. Sie können die WHERE-Klausel nicht verwenden, um die gelöschten Zeilen zu begrenzen. Es werden keine Trigger ausgelöst. 

  2. Wenn Sie dagegen mehr als 80-90 Prozent der Daten löschen, sagen Sie, wenn Sie insgesamt 11 Millionen Zeilen haben und 10 Millionen löschen möchten. Eine andere Möglichkeit wäre das Einfügen dieser 1 Million Zeilen (Datensätze, die Sie behalten möchten.) ) zu einer anderen Staging-Tabelle. Schneiden Sie diese große Tabelle ab und fügen Sie diese 1 Million Zeilen ein. 

  3. Wenn Berechtigungen/Ansichten oder andere Objekte, die diese große Tabelle als zugrunde liegende Tabelle enthalten, nicht durch das Ablegen dieser Tabelle beeinträchtigt werden, können Sie diese relativ kleine Menge der Zeilen in eine andere Tabelle laden, diese Tabelle löschen und eine andere Tabelle mit demselben Schema erstellen und diese importieren Zeilen zurück in diese ex-Large-Tabelle.

  4. Eine letzte Option, die ich mir vorstellen kann, ist, den Recovery Mode to SIMPLE Ihrer Datenbank zu ändern und dann Zeilen in kleineren Stapeln zu löschen, indem Sie eine while-Schleife verwenden.

    DECLARE @Deleted_Rows INT;
    SET @Deleted_Rows = 1;
    
    
    WHILE (@Deleted_Rows > 0)
      BEGIN
       -- Delete some small number of rows at a time
         DELETE TOP (10000)  LargeTable 
         WHERE readTime < dateadd(MONTH,-7,GETDATE())
    
      SET @Deleted_Rows = @@ROWCOUNT;
    END
    

vergessen Sie nicht, den Wiederherstellungsmodus wieder vollständig zu ändern, und ich denke, Sie müssen eine Sicherungskopie erstellen, um sie vollständig zu aktivieren (Änderungs- oder Wiederherstellungsmodus).

147
M.Ali

@ m-ALi Antwort ist richtig, aber bedenken Sie auch, dass die Protokolle stark anwachsen können, wenn Sie die Transaktion nicht nach jedem Block festschreiben und einen Prüfpunkt ausführen. So würde ich es tun und diesen Artikel http://sqlperformance.com/2013/03/io-subsystem/chunk-deletes als Referenz nehmen, mit Leistungstests und Grafiken:

DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;


WHILE (@Deleted_Rows > 0)
  BEGIN

   BEGIN TRANSACTION

   -- Delete some small number of rows at a time
     DELETE TOP (10000)  LargeTable 
     WHERE readTime < dateadd(MONTH,-7,GETDATE())

     SET @Deleted_Rows = @@ROWCOUNT;

   COMMIT TRANSACTION
   CHECKPOINT -- for simple recovery model
END
63

Sie können GO + auch verwenden, wie oft Sie dieselbe Abfrage ausführen möchten. 

DELETE TOP (10000)  [TARGETDATABASE].[SCHEMA].[TARGETTABLE] 
WHERE readTime < dateadd(MONTH,-1,GETDATE());
-- how many times you want the query to repeat
GO 100
34
Bunkerbuster

Diese Variation von M.ALi 's funktioniert gut für mich. Es löscht einige, löscht das Protokoll und wiederholt sich. Ich beobachte, wie das Protokoll wächst, fällt und von vorne beginnt.

DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;
WHILE (@Deleted_Rows > 0)
  BEGIN
   -- Delete some small number of rows at a time
    delete top (100000) from InstallLog where DateTime between '2014-12-01' and '2015-02-01'
    SET @Deleted_Rows = @@ROWCOUNT;
    dbcc shrinkfile (MobiControlDB_log,0,truncateonly);
END
8
Ken Koehler

@Francisco Goldenstein, nur eine kleine Korrektur. Der COMMIT muss verwendet werden, nachdem Sie die Variable festgelegt haben. Andernfalls wird die WHILE-Anweisung nur einmal ausgeführt:

DECLARE @Deleted_Rows INT;
SET @Deleted_Rows = 1;

WHILE (@Deleted_Rows > 0)
BEGIN
    BEGIN TRANSACTION

    -- Delete some small number of rows at a time
    DELETE TOP (10000)  LargeTable 
    WHERE readTime < dateadd(MONTH,-7,GETDATE())

    SET @Deleted_Rows = @@ROWCOUNT;

    COMMIT TRANSACTION
    CHECKPOINT -- for simple recovery model

END
8
Cassio Veras

Wenn Sie bereit sind (und können), Partitionierung zu implementieren, ist dies eine effektive Methode zum Entfernen großer Datenmengen mit geringem Laufzeitaufwand. Nicht kosteneffektiv für eine einmalige Übung.

7
Michael Green

Ich konnte innerhalb von Minuten19 Millionen Zeilen aus meiner Tabelle mit 21 Millionen Zeilen löschen. Hier ist mein Ansatz.

Wenn Sie für diese Tabelle einen automatisch inkrementierenden Primärschlüssel haben, können Sie diesen Primärschlüssel verwenden.

  1. Ruft den Mindestwert des Primärschlüssels der großen Tabelle ab, wobei readTime <dateadd (MONTH, -7, GETDATE ()) ist. (Fügen Sie einen Index für readTime hinzu. Falls noch nicht vorhanden, wird dieser Index in Schritt 3 zusammen mit der Tabelle gelöscht.). Lass es in einer Variablen 'min_primary' speichern

  2. Fügen Sie alle Zeilen mit dem Primärschlüssel> min_primary in eine Staging-Tabelle ein (Speichertabelle, wenn die Zeilenanzahl nicht groß ist). 

  3. Lass den großen Tisch fallen.

  4. Erstellen Sie die Tabelle neu. Kopieren Sie alle Zeilen aus der Staging-Tabelle in die Haupttabelle.

  5. Lassen Sie die Staging-Tabelle fallen.

4
Arpan Jain

Sie können kleine Stapel mit einer while-Schleife löschen, etwa wie folgt:

DELETE TOP (10000)  LargeTable 
WHERE readTime < dateadd(MONTH,-7,GETDATE())
WHILE @@ROWCOUNT > 0
BEGIN
    DELETE TOP (10000)  LargeTable 
    WHERE readTime < dateadd(MONTH,-7,GETDATE())
END
3
fnascimento

Eine andere Verwendung:

SET ROWCOUNT 1000 -- Buffer

DECLARE @DATE AS DATETIME = dateadd(MONTH,-7,GETDATE())

DELETE LargeTable  WHERE readTime < @DATE
WHILE @@ROWCOUNT > 0
BEGIN
   DELETE LargeTable  WHERE readTime < @DATE
END
SET ROWCOUNT 0

Wahlweise; 

Wenn das Transaktionsprotokoll aktiviert ist, deaktivieren Sie die Transaktionsprotokolle.

ALTER DATABASE dbname SET RECOVERY SIMPLE;
2
Ali Osman Yavuz

Kürzere Syntax 

select 1
WHILE (@@ROWCOUNT > 0)
BEGIN
  DELETE TOP (10000) LargeTable 
  WHERE readTime < dateadd(MONTH,-7,GETDATE())
END
1
paparazzo

Wenn Sie SQL Server 2016 oder höher verwenden und in Ihrer Tabelle Partitionen erstellt werden, die auf der zu löschenden Spalte basieren (z. B. Timestamp-Spalte), können Sie diesen neuen Befehl verwenden, um Daten nach Partitionen zu löschen.

TRUNCATE TABLE WITH (PARTITIONS ({|} [ ... n])) 

Dadurch werden nur die Daten in den ausgewählten Partitionen gelöscht. Dies sollte die effizienteste Methode zum Löschen von Daten aus einem Teil der Tabelle sein, da keine Transaktionsprotokolle erstellt werden und genauso schnell ausgeführt werden wie das reguläre Abschneiden, jedoch ohne dass alle Daten gelöscht werden vom Tisch.

Der Nachteil ist, wenn Ihre Tabelle nicht mit Partition eingerichtet ist, müssen Sie die Daten der alten Schule löschen und die Daten regelmäßig löschen. Anschließend müssen Sie die Tabelle mit Partitionen neu erstellen, damit Sie dies in Zukunft tun können, was ich auch getan habe. Ich habe die Partitionserstellung und das Löschen in das Einfügeverfahren selbst eingefügt. Ich hatte eine Tabelle mit 500 Millionen Zeilen, daher war dies die einzige Möglichkeit, die Löschzeit zu reduzieren.

Weitere Informationen finden Sie unter den folgenden Links: https://docs.Microsoft.com/en-us/sql/t-sql/statements/truncate-table-transact-sql?view=sql-server-2017

SQL Server 2016 Tabelle mit Partitionen abschneiden

Nachfolgend habe ich zuerst die Daten gelöscht, bevor ich die Tabelle mit Partitionen mit den erforderlichen Daten neu erstellen konnte. Diese Abfrage wird für einige Tage im angegebenen Zeitfenster ausgeführt, bis die Daten gelöscht werden.

:connect <<ServerName>>
use <<DatabaseName>>

SET NOCOUNT ON;
DECLARE @Deleted_Rows INT;
DECLARE @loopnum INT;
DECLARE @msg varchar(100);
DECLARE @FlagDate datetime;
SET @FlagDate =  getdate() - 31;
SET @Deleted_Rows = 1;
SET @loopnum = 1;

/*while (getdate() < convert(datetime,'2018-11-08 14:00:00.000',120))
BEGIN
    RAISERROR( 'WAIT for START' ,0,1) WITH NOWAIT   
    WAITFOR DELAY '00:10:00'
END*/
RAISERROR( 'STARTING PURGE' ,0,1) WITH NOWAIT   

WHILE (1=1)
BEGIN
    WHILE (@Deleted_Rows > 0 AND (datepart(hh, getdate() ) >= 12 AND datepart(hh, getdate() ) <= 20)) -- (getdate() < convert(datetime,'2018-11-08 19:00:00.000',120) )
      BEGIN
       -- Delete some small number of rows at a time
         DELETE TOP (500000)  dbo.<<table_name>>
         WHERE timestamp_column < convert(datetime, @FlagDate,102)
         SET @Deleted_Rows = @@ROWCOUNT;
         WAITFOR DELAY '00:00:01'
         select @msg = 'ROWCOUNT' + convert(varchar,@Deleted_Rows);
         set @loopnum = @loopnum + 1
         if @loopnum > 1000
             begin 
                 begin try
                        DBCC SHRINKFILE (N'<<databasename>>_log' , 0, TRUNCATEONLY)
                        RAISERROR( @msg ,0,1) WITH NOWAIT
                 end try
                 begin catch
                     RAISERROR( 'DBCC SHRINK' ,0,1) WITH NOWAIT  
                 end catch
                 set @loopnum = 1
             end
        END
WAITFOR DELAY '00:10:00'
END 
select getdate()
0