Domanda

Questa è stata un'avventura. Ho iniziato con la query duplicata in loop situata in la mia domanda precedente , ma ogni ciclo avrebbe superato tutti i 17 milioni di record , significa che occorrerebbero settimane (solo l'esecuzione di * select count * da MyTable * richiede il mio server 4:30 minuti usando MSSQL 2005). Ho brillato di informazioni da questo sito e in questo post .

E sono arrivato alla query qui sotto. La domanda è: è questo il tipo corretto di query da eseguire su 17 milioni di record per qualsiasi tipo di prestazione? In caso contrario, cos'è?

SQL QUERY:

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)
È stato utile?

Soluzione

Vedere il QueryPlan sarebbe di aiuto.

È possibile?

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

Altri suggerimenti

Qualcosa non va con il tuo DB, server, memoria o una combinazione di questi. 4:30 per un conteggio selezionato * sembra MOLTO alto.

Esegui un DBCC_SHOWCONTIG per vedere quanto è frammentata la tua tabella, questo potrebbe causare un notevole calo delle prestazioni su una tabella di quelle dimensioni.

Inoltre, per aggiungere al commento di RyanKeeter, esegui il piano dello spettacolo e se ci sono scansioni di tabelle crea un indice per il campo PK su quella tabella.

Non sarebbe più semplice da fare:

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
  )

Esegui questo nell'analizzatore di query:

SET SHOWPLAN_TEXT ON

Quindi chiedi all'analizzatore di query di eseguire la tua query. Invece di eseguire la query, SQL Server genererà un piano di query e lo inserirà nel set di risultati.

Mostraci il piano di query.

17 milioni di record non sono niente. Se sono necessarie le 4:30 per eseguire solo un conteggio selezionato (*), si verifica un problema grave, probabilmente correlato alla mancanza di memoria nel server o a un processore davvero vecchio.

Per prestazioni, riparare la macchina. Pompalo fino a 2 GB. La RAM è così economica in questi giorni che il suo costo è molto inferiore al tuo tempo.

Il processore o il disco si sta bloccando quando la query è in corso? In caso contrario, qualcosa sta bloccando le chiamate. In tal caso, potresti considerare di mettere il database in modalità utente singolo per il tempo necessario per eseguire la pulizia.

Quindi stai eliminando tutti i record che non sono classificati per primi? Potrebbe valere la pena confrontare un join con una delle prime 1 sub query (che potrebbe funzionare anche nel 2000, poiché il grado è solo il 2005 e oltre)

Devi rimuovere tutti i duplicati in un'unica operazione? Presumo che tu stia eseguendo una sorta di compito di pulizia, potresti essere in grado di farlo saggiamente.

Fondamentalmente creare un cursore che avvolge tutti i record (lettura sporca) e rimuove i duplicati per ciascuno. Nel complesso sarà molto più lento, ma ogni operazione sarà relativamente minima. Quindi le pulizie diventano un'attività in background costante anziché un batch notturno.

Il suggerimento sopra per selezionare prima un tavolo temporaneo è la soluzione migliore. Puoi anche usare qualcosa come:

set rowcount 1000

prima di eseguire la tua cancellazione. Smetterà di funzionare dopo aver eliminato le 1000 righe. Quindi eseguilo ancora e ancora fino a quando non ottieni 0 record cancellati.

se lo capisco correttamente, la tua richiesta è uguale a

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

Penso che dovrebbe funzionare più velocemente, tendo ad evitare di utilizzare " IN " clausola a favore dei JOIN ove possibile.

Puoi effettivamente testare la velocità e i risultati in modo sicuro semplicemente chiamando SELECT * o SELECT COUNT (*) sulla parte FROM come ad esempio

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

Questo è un altro motivo per cui preferirei l'approccio JOIN Spero che ciò aiuti

Questo sembra a posto ma potresti prendere in considerazione la possibilità di selezionare i tuoi dati in una tabella temporanea e di usarli nella tua dichiarazione di eliminazione. Ho notato enormi miglioramenti delle prestazioni facendo questo invece di fare tutto in quell'unica query.

Ricorda che quando esegui una cancellazione di grandi dimensioni è meglio avere prima un buon backup (e di solito copio anche i record eliminati su un'altra tabella per ogni evenienza, devo recuperarli subito).

Oltre a utilizzare troncato come suggerito, ho avuto la fortuna di utilizzare questo modello per eliminare molte righe da una tabella. Non ricordo di esserlo, ma penso che l'utilizzo della transazione abbia contribuito a impedire la crescita del file di registro - potrebbe essere stato un altro motivo - non sono sicuro. E di solito cambio il metodo di registrazione delle transazioni su semplice prima di fare qualcosa del genere:

SET ROWCOUNT 5000
WHILE 1 = 1
BEGIN
    begin tran
            DELETE FROM ??? WHERE ???
            IF @@rowcount = 0
            BEGIN
               COMMIT
               BREAK
            END
    COMMIT
END
SET ROWCOUNT 0
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top