2012-03-30 15 views
9

Sto tentando di utilizzare Dapper per l'accesso ai miei dati per l'app del mio server.Metodo corretto per eliminare oltre 2100 righe (per ID) con Dapper

L'app del mio server ha un'altra applicazione che rilascia record nel mio database a una velocità di 400 al minuto.

La mia app li estrae in batch, li elabora e li elimina dal database.

Poiché i dati continuano a scorrere nel database mentre sto elaborando, non ho un buon modo per dire delete from myTable where allProcessed = true.

Tuttavia, conosco il valore PK delle righe da eliminare. Quindi voglio fare un

Il problema è che se il mio server si ferma per almeno 6 minuti, allora ho più di 2100 righe da eliminare.

Da quando Dapper prende il mio @listToDelete e trasforma ciascuno di essi in un parametro, la mia chiamata all'eliminazione fallisce. (Causa lo spurgo dei miei dati per ottenere ancora più indietro.)

Qual è il modo migliore per gestire questo in Dapper?

NOTE: Ho esaminato i Parametri valutati su Tabled ma da quello che posso vedere, non sono molto performant. Questo pezzo della mia architettura è il collo di bottiglia del mio sistema e ho bisogno di essere molto molto veloce.

+0

@marc_s - Non ho ** bisogno ** di passare molti parametri ... Ma ho bisogno di cancellare quelle righe per ID PK. Comunque lo faccio va bene per me. Sto dicendo dapper di cancellare ogni riga nel mio '@ list'. È Dapper che sta facendo i parametri di ogni elemento nella mia lista. – Vaccano

+0

Difficile dire da questa piccola informazione, ma perché non è possibile utilizzare i criteri di selezione per il batch come criterio per l'eliminazione. Oppure disporre di un flag elaborato in MyTable, impostarlo in "elaborazione" e quindi utilizzarlo. Non è bello, ma sarà molto più rapido che cancellarli uno per uno. Non sarà terribilmente pessimo nemmeno con 10.000 dischi. –

+0

I miei criteri di lotto non sono molto performanti. Quindi preferirei non usarlo. Potrei aggiungere un flag elaborato, ma per farlo avrei bisogno di un modo per richiamare le righe per aggiungere il flag elaborato a. Se riesco a chiamarli, posso anche eliminarli. (Potrei aggiungere una bandiera per dire "in batch" al momento opportuno, ma preferirei non farlo.) – Vaccano

risposta

12

Un'opzione è creare una tabella temporanea sul server e quindi utilizzare la funzione di caricamento di massa per caricare tutti gli ID in quella tabella contemporaneamente. Quindi utilizzare una clausola join, EXISTS o IN per eliminare solo i record caricati nella tabella temporanea.

I carichi di massa sono un percorso ottimizzato in SQL Server e dovrebbero essere molto veloci.

Ad esempio:

  1. Eseguire l'istruzione CREATE TABLE #RowsToDelete(ID INT PRIMARY KEY)
  2. Utilizzare un caricamento di massa per inserire le chiavi in ​​#RowsToDelete
  3. Execute DELETE FROM myTable where Id IN (SELECT ID FROM #RowsToDelete)
  4. Execute DROP TABLE #RowsToDelte (la tabella sarà anche essere eliminato automaticamente se si chiude la sessione)

(Supponendo Dapper) esempio di codice:

conn.Open(); 

var columnName = "ID"; 

conn.Execute(string.Format("CREATE TABLE #{0}s({0} INT PRIMARY KEY)", columnName)); 

using (var bulkCopy = new SqlBulkCopy(conn)) 
{ 
    bulkCopy.BatchSize = ids.Count; 
    bulkCopy.DestinationTableName = string.Format("#{0}s", columnName); 

    var table = new DataTable();      
    table.Columns.Add(columnName, typeof (int)); 
    bulkCopy.ColumnMappings.Add(columnName, columnName); 

    foreach (var id in ids) 
    { 
     table.Rows.Add(id); 
    } 

    bulkCopy.WriteToServer(table); 
} 

//or do other things with your table instead of deleting here 
conn.Execute(string.Format(@"DELETE FROM myTable where Id IN 
            (SELECT {0} FROM #{0}s", columnName)); 

conn.Execute(string.Format("DROP TABLE #{0}s", columnName)); 
+0

Aggiunto codice di esempio che effettivamente utilizza SqlBulkCopy, potrebbe essere adattato per tabelle più ampie aggiungendo più colonne a temp tabella e tabella dati. –

5

Per far funzionare questo codice, sono andato al lato oscuro.

Da quando Dapper rende la mia lista in parametri. E SQL Server non può gestire molti parametri. (Non ho mai avuto bisogno nemmeno di parametri a doppia cifra prima). Dovevo andare con Dynamic SQL.

Così qui è stata la mia soluzione:

string listOfIdsJoined = "("+String.Join(",", listOfIds.ToArray())+")"; 
connection.Execute("delete from myTable where Id in " + listOfIdsJoined); 

prima di tutti afferra le loro torce e forconi, lascia che ti spieghi.

  • Questo codice viene eseguito su un server il cui unico input è un feed di dati da un sistema Mainframe.
  • L'elenco che sto creando dinamicamente è un elenco di longs/bigints.
  • I long/bigin provengono da una colonna Identity.

So che la costruzione di SQL dinamico è male juju, ma in questo caso, non riesco proprio a vedere come ciò comporti un rischio per la sicurezza.

+2

[Little Bobby Tables] (https://xkcd.com/327/) say's G'Day! –

+3

@ Pure.Krome presumibilmente il suo 'listOfIds' è di tipo' Lista 'quindi non è necessario disinfettare gli ingressi – Zac

+0

Probabilmente ... ma le ipotesi sono la radice di tutti i mali. In secondo luogo, è il suggerimento generale => creare uno script sql, al volo e in una stringa ... potrebbe finire molto male :) –

2

Dapper richiesta Elenco dell'oggetto avente parametro come proprietà quindi in caso di sopra di un elenco di oggetti avente Id come proprietà funzionerà.

connection.Execute("delete from myTable where Id in (@Id)", listOfIds.AsEnumerable().Select(i=> new { Id = i }).ToList()); 

Questo funzionerà.

Problemi correlati