2010-04-01 40 views
5

Tengo una tabla que contiene entradas de registro para un programa que estoy escribiendo. Estoy buscando ideas sobre una consulta SQL (estoy usando SQL Server Express 2005) que mantendrá el número más reciente de registros X, y eliminaré el resto. Tengo una columna de fecha y hora que es una marca de tiempo para la entrada de registro.Consulta SQL para eliminar filas más antiguas en un determinado recuento de filas?

Me parece algo así como lo siguiente, pero no estoy seguro del rendimiento con la cláusula IN para un mayor número de registros. El rendimiento no es crítico, pero podría hacerlo lo mejor que pueda la primera vez.

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

debería mencionar que esta consulta se ejecutará 3-4 veces al día (como parte de otro proceso), por lo que el número de registros que se eliminará con cada consulta será pequeño en comparación con el número de registros que se mantendrán.

+0

¿Lo has probado? ¿Funciona bien?SI no es crítico, y lo que tienes funciona, es bastante obvio lo que está sucediendo, y es "lo suficientemente rápido" ir con él. – Nate

+0

No lo he probado, pero debería funcionar. Admito que soy culpable de optimizar demasiado, es un mal hábito. –

Respuesta

3

Prueba esto:

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 
        ) 

tipo de depende de si se va a eliminar menos de 10.000 filas, si es así esto podría correr más rápido, ya que identifica las filas de borrar, no las filas de mantener.

1

La consulta que tiene es casi tan eficiente como se puede y es legible.

NOT IN y NOT EXISTS son más eficientes que LEFT JOIN/IS NULL, pero solo porque ambas columnas nunca pueden ser nulas. Puede 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)) 

o

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

No estoy seguro si se trata de una mejora en cuanto a la eficiencia sin embargo.

1

Esto depende de su escenario (si es factible para usted) y cuántas filas tiene, pero existe un enfoque potencialmente mucho más óptimo.

  1. crear una nueva copia de la tabla de registro con un nombre nuevo
  2. insertar en la nueva tabla, los más recientes 10.000 registros de la tabla original
  3. gota la tabla original (o renombrar)
  4. Cambie el nombre de la nueva tabla al nombre propio

Obviamente, esto requiere más reflexión que simplemente eliminar filas (por ejemplo, si la tabla tiene una columna IDENTIDAD, debe establecerse en la nueva tabla, etc.). Pero si tiene una tabla grande, sería más eficiente copiar 10.000 filas en una nueva tabla y luego soltar la tabla original, que tratar de eliminar millones de filas para dejar solo 10.000.

2

Pruebe esto, usa un CTE para obtener el número ordinal de la fila, y luego solo borra el número X de filas a la vez. Puede modificar esta variable para adaptarse a su servidor.

La adición de la sugerencia de la tabla ReadPast debe evitar el bloqueo.

:

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; 
Cuestiones relacionadas