Pregunta

Esto ha sido una aventura. Comencé con la consulta duplicada en bucle ubicada en mi pregunta anterior , pero cada bucle repasaría todos los 17 millones de registros , significa que tomaría semanas (simplemente ejecutando * select count * from MyTable * toma mi servidor 4:30 minutos usando MSSQL 2005). Recopilé información de este sitio y en este publicación .

Y he llegado a la consulta de abajo. La pregunta es, ¿es este el tipo correcto de consulta para ejecutar en 17 millones de registros para cualquier tipo de rendimiento? Si no lo es, ¿qué es?

CONSULTA DE SQL:

DELETE tl_acxiomimport.dbo.tblacxiomlistings
WHERE RecordID in 
(SELECT RecordID
    FROM tl_acxiomimport.dbo.tblacxiomlistings
    EXCEPT
    SELECT RecordID
    FROM (
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude,           Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
    FROM tl_acxiomimport.dbo.tblacxiomlistings
    ) al WHERE Rank = 1)
¿Fue útil?

Solución

Ver el QueryPlan ayudaría.

¿Es esto factible?

SELECT m.*
into #temp
FROM tl_acxiomimport.dbo.tblacxiomlistings m 
inner join (SELECT RecordID, 
                   Rank() over (Partition BY BusinessName, 
                                             latitude,  
                                             longitude,            
                                             Phone  
                                ORDER BY webaddress DESC,  
                                         caption1 DESC,  
                                         caption2 DESC ) AS Rank
              FROM tl_acxiomimport.dbo.tblacxiomlistings
           ) al on (al.RecordID = m.RecordID and al.Rank = 1)

truncate table tl_acxiomimport.dbo.tblacxiomlistings

insert into tl_acxiomimport.dbo.tblacxiomlistings
     select * from #temp

Otros consejos

Algo está en tu base de datos, servidor, almacenamiento o alguna combinación de ellos. 4:30 para un conteo selecto * parece MUY alto.

Ejecute un DBCC_SHOWCONTIG para ver qué tan fragmentada está su tabla, esto podría causar un gran impacto en el rendimiento de una tabla de ese tamaño.

Además, para agregar al comentario de RyanKeeter, ejecute el plan de presentación y, si hay exploraciones de tablas, cree un índice para el campo PK en esa tabla.

¿No sería más sencillo de hacer?

DELETE tl_acxiomimport.dbo.tblacxiomlistings
WHERE RecordID in 
(SELECT RecordID
   FROM (
        SELECT RecordID,
            Rank() over (Partition BY BusinessName,
                                  latitude,
                                  longitude,
                                  Phone
                         ORDER BY webaddress DESC,
                                  caption1 DESC,
                                  caption2 DESC) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        )
  WHERE Rank > 1
  )

Ejecuta esto en el analizador de consultas:

SET SHOWPLAN_TEXT ON

Luego pregunte al analizador de consultas para ejecutar su consulta. En lugar de ejecutar la consulta, SQL Server generará un plan de consulta y lo colocará en el conjunto de resultados.

Muéstrenos el plan de consulta.

17 millones de discos no es nada. Si se necesita 4:30 para hacer solo un conteo selectivo (*), entonces hay un problema grave, probablemente relacionado con la falta de memoria en el servidor o con un procesador realmente antiguo.

Para mejorar el rendimiento, arregla la máquina. Bombee hasta 2GB. La memoria RAM es tan barata en estos días que su costo es mucho menor que su tiempo.

¿Se está activando el procesador o el disco cuando se realiza la consulta? Si no, entonces algo está bloqueando las llamadas. En ese caso, podría considerar poner la base de datos en modo de usuario único por la cantidad de tiempo que lleva ejecutar la limpieza.

¿Así que estás eliminando todos los registros que no están clasificados primero? Podría valer la pena comparar una unión con una sub consulta superior (contra) (lo que también podría funcionar en 2000, ya que el rango es 2005 y superior solamente)

¿Necesita eliminar todos los duplicados en una sola operación? Supongo que está realizando algún tipo de tarea de mantenimiento, es posible que pueda hacerlo por partes.

Básicamente, cree un cursor que recorra todos los registros (lectura sucia) y elimine duplicados para cada uno. En general, será mucho más lento, pero cada operación será relativamente mínima. Entonces su limpieza se convierte en una tarea constante en segundo plano en lugar de un lote nocturno.

La sugerencia anterior para seleccionar primero en una tabla temporal es su mejor apuesta. También puedes usar algo como:

set rowcount 1000

antes de ejecutar su eliminación. Se detendrá después de eliminar las 1000 filas. Luego ejecútalo una y otra vez hasta que elimines 0 registros.

si lo consigo correctamente, tu consulta es la misma que

DELETE tl_acxiomimport.dbo.tblacxiomlistings
FROM
    tl_acxiomimport.dbo.tblacxiomlistings allRecords
    LEFT JOIN (   
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude, Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        WHERE Rank = 1) myExceptions
    ON allRecords.RecordID = myExceptions.RecordID
WHERE
    myExceptions.RecordID IS NULL

Creo que debería ejecutarse más rápido, tiendo a evitar el uso de " IN " Cláusula a favor de JOINs cuando sea posible.

Puede probar la velocidad y los resultados de forma segura simplemente llamando a SELECT * o SELECT COUNT (*) en la parte FROM como por ejemplo

SELECT *
FROM
    tl_acxiomimport.dbo.tblacxiomlistings allRecords
    LEFT JOIN (   
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude, Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        WHERE Rank = 1) myExceptions
    ON allRecords.RecordID = myExceptions.RecordID
WHERE
    myExceptions.RecordID IS NULL

Esa es otra razón por la que preferiría el enfoque JOIN Espero que eso ayude

Esto se ve bien pero puede considerar seleccionar sus datos en una tabla temporal y usarlos en su declaración de eliminación. He notado enormes ganancias de rendimiento al hacer esto en lugar de hacerlo todo en esa única consulta.

Recuerde que cuando realice una eliminación grande, es mejor tener una buena copia de seguridad primero (y, por lo general, también copio los registros eliminados en otra tabla por si acaso, necesito recuperarlos de inmediato).

Aparte de usar Truncate como se sugiere, he tenido la mejor suerte al usar esta plantilla para eliminar muchas filas de una tabla. No recuerdo de antemano, pero creo que el uso de la transacción ayudó a evitar que el archivo de registro crezca, aunque puede haber sido otra razón, no estoy seguro. Y, por lo general, cambio el método de registro de transacciones a simple antes de hacer algo como esto:

SET ROWCOUNT 5000
WHILE 1 = 1
BEGIN
    begin tran
            DELETE FROM ??? WHERE ???
            IF @@rowcount = 0
            BEGIN
               COMMIT
               BREAK
            END
    COMMIT
END
SET ROWCOUNT 0
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top