2010-04-01 25 views
5

Mam tabelę, która zawiera wpisy dziennika dla programu, który piszę. Szukam pomysłów na zapytanie SQL (używam programu SQL Server Express 2005), który zachowa najnowszą liczbę rekordów X i usunie pozostałe. Mam kolumnę datetime, która jest znacznikiem czasu dla wpisu dziennika.Zapytanie SQL do usuwania najstarszych wierszy powyżej pewnej liczby wierszy?

Myślę, że coś takiego działa, ale nie jestem pewien wydajności z klauzulą ​​IN dla większej liczby rekordów. Wydajność nie jest krytyczna, ale równie dobrze mogę zrobić wszystko, co mogę za pierwszym razem.

DELETE FROM MyTable WHERE PrimaryKey NOT IN 
(SELECT TOP 10,000 PrimaryKey FROM MyTable ORDER BY TimeStamp DESC) 

należy wspomnieć, że ta kwerenda będzie działać 3-4 razy dziennie (jako część innego procesu), więc liczba rekordów, które zostaną usunięte z każdego zapytania będzie niewielki w porównaniu do liczby zapisy, które będą przechowywane.

+0

Czy próbowałeś go? Czy to działa dobrze?JEŚLI nie jest to krytyczne i to, co robisz, jest dość oczywiste, co się dzieje i jest "wystarczająco szybkie". – Nate

+0

Nie próbowałem, ale powinno działać. Przyznaję, że jestem winny nadmiernej optymalizacji, to zły nawyk. –

Odpowiedz

3

Spróbuj tego:

DECLARE @X int 
SELECT @X=COUNT(*) FROM MyTable 
SET @[email protected] 

DELETE MyTable 
WHERE PrimaryKey IN (SELECT TOP(@x) PrimaryKey 
        FROM MyTable 
        ORDER BY TimeStamp ASC 
        ) 

rodzaj zależy od tego, czy usuwasz mniej niż 10000 wierszy, jeśli tak to może działać szybciej, gdyż identyfikuje wiersze do usunięcia, nie wiersze zachować.

1

Zapytanie, które masz, jest tak wydajne, jak to tylko możliwe, i można je odczytać.

NOT IN i NOT EXISTS są bardziej wydajne niż LEFT JOIN/IS NULL, ale tylko dlatego, że obie kolumny nigdy nie mogą mieć wartości null. Możesz read this link for a more in-depth comparison.

1
DELETE FROM MyTable 
WHERE TimeStamp < (SELECT min(TimeStamp) 
        FROM (SELECT TOP 10,000 TimeStamp 
         FROM MyTable 
         ORDER BY TimeStamp DESC)) 

lub

DELETE FROM MyTable 
WHERE TimeStamp < (SELECT min(TimeStamp) 
        FROM MyTable 
        WHERE PrimaryKey IN (SELECT TOP 10,000 TimeStamp 
             FROM MyTable 
             ORDER BY TimeStamp DESC)) 

Nie wiem, czy są one w miarę poprawy efektywności chociaż.

1

To zależy od twojego scenariusza (czy jest to wykonalne dla ciebie) i liczby rzędów, ale istnieje potencjalnie znacznie bardziej optymalne podejście.

  1. Utwórz nową kopię tabeli dziennika z nową nazwą
  2. wstawić do nowej tabeli, najnowsze 10000 rekordy z tabeli pierwotnej
  3. upuść oryginalny stół (lub zmienić nazwę)
  4. Zmień nazwę nowej tabeli na poprawną nazwę

To oczywiście wymaga więcej myślenia niż po prostu usuwanie wierszy (np. Jeśli tabela ma kolumnę IDENTITY to należy ustawić na nowej tablicy itp.). Ale jeśli masz duży stół, skuteczniej byłoby skopiować 10 000 wierszy do nowego stołu, a następnie upuścić pierwotną tabelę, niż próbować usunąć miliony wierszy, aby pozostawić tylko 10 000.

2

Spróbuj tego, używa CTE, aby uzyskać numer porządkowy wiersza, a następnie usuwa tylko X liczby wierszy na raz. Możesz zmienić tę zmienną, aby pasowała do twojego serwera.

Dodanie podpowiedzi do tablicy ReadPast powinno zapobiegać blokowaniu.

:

DECLARE @numberToDelete INT; 
DECLARE @ROWSTOKEEP INT; 
SET @ROWSTOKEEP = 50000; 
SET @numberToDelete =1000; 

WHILE 1=1 
BEGIN 
    WITH ROWSTODELETE AS 
    (
     SELECT ROW_NUMBER() OVER(ORDER BY dtsTimeStamp DESC) rn, 
      * 
     FROM MyTable 

    ) 
    DELETE TOP (@numberToDelete) FROM ROWSTODELETE WITH(READPAST) 
    WHERE rn>@ROWSTOKEEP; 

    IF @@ROWCOUNT=0 
     BREAK; 
END; 
Powiązane problemy