2012-03-30 13 views
9

Ich versuche zu verwenden Dapper Unterstützung meines Datenzugriffs für meine Server-App.Korrekte Methode zum Löschen von mehr als 2100 Zeilen (nach ID) mit Dapper

Meine Server-App verfügt über eine andere Anwendung, die Datensätze mit einer Rate von 400 pro Minute in meine Datenbank löscht.

Meine App zieht sie in Stapeln, verarbeitet sie und löscht sie dann aus der Datenbank.

Da Daten während der Verarbeitung weiterhin in die Datenbank fließen, habe ich keine gute Möglichkeit, delete from myTable where allProcessed = true zu sagen.

Allerdings kenne ich den PK-Wert der Zeilen zu löschen. Also ich möchte ein delete from myTable where Id in @listToDelete

Problem ist, dass, wenn mein Server für noch 6 Minuten ausfällt, dann habe ich über 2100 Zeilen zu löschen.

Da Dapper meine @listToDelete übernimmt und jede in einen Parameter verwandelt, schlägt mein Aufruf zum Löschen fehl. (Verursacht, dass meine Daten bereinigt werden, um noch weiter zurück zu kommen.)

Was ist der beste Weg, damit in Dapper umzugehen?

NOTES: Ich habe Tabled bewertete Parameter angeschaut, aber von dem, was ich sehen kann, sind sie nicht sehr performant. Dieses Stück meiner Architektur ist der Flaschenhals meines Systems und ich muss sehr schnell sein sehr.

+0

@marc_s - Ich brauche ** nicht, um so viele Parameter zu übergeben ... Aber ich muss diese vielen Zeilen durch PK Id löschen. Wie dem auch sei, das ist für mich in Ordnung. Ich sage adrett, jede Zeile in meiner @ -Liste zu löschen. Es ist Dapper, der Parameter von jedem Gegenstand in meiner Liste macht. – Vaccano

+0

Aus diesen wenigen Informationen ist das schwer zu ersehen, aber warum können Sie die Auswahlkriterien für Batch nicht als Kriterium für ein Löschen verwenden? Oder habe eine verarbeitete Markierung in MyTable, setze sie in der "Verarbeitung" und verwende sie dann. Es ist nicht brillant, aber es wird viel schneller sein, als sie nacheinander zu löschen. Es wird nicht erschreckend schlecht sein, selbst mit 10.000 Datensätzen. –

+0

Meine Batch-Kriterien sind nicht sehr performant. Also würde ich es vorziehen, das nicht zu benutzen. Ich könnte ein verarbeiteter Flag hinzufügen, aber dazu müsste ich die Zeilen aufrufen, denen das verarbeitete Flag hinzugefügt werden soll. Wenn ich sie anrufen kann, kann ich sie auch löschen. (Ich könnte eine Flagge hinzufügen, um zu sagen, "Batched" zur ausgewählten Zeit. Aber ich würde lieber nicht.) – Vaccano

Antwort

12

Eine Option besteht darin, eine temporäre Tabelle auf dem Server zu erstellen und dann die Massenladefunktion zu verwenden, um alle IDs gleichzeitig in diese Tabelle hochzuladen. Verwenden Sie dann eine Join-, EXISTS- oder IN-Klausel, um nur die Datensätze zu löschen, die Sie in Ihre temporäre Tabelle hochgeladen haben.

Massenlasten sind ein optimierter Pfad in SQL Server und sollten sehr schnell sein.

Zum Beispiel:

  1. Führen Sie die Anweisung CREATE TABLE #RowsToDelete(ID INT PRIMARY KEY)
  2. Verwendung eines Massenladeschlüssel in #RowsToDelete
  3. Execute DELETE FROM myTable where Id IN (SELECT ID FROM #RowsToDelete)
  4. ausführen DROP TABLE #RowsToDelte (die Tabelle auch fallen gelassen werden einfügen wird automatisch, wenn Sie in der Nähe die Sitzung)

(Unter der Annahme, Dapper) Code-Beispiel:

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

Hinzugefügt Beispielcode, der tatsächlich SqlBulkCopy verwendet, könnte für breitere Tabellen angepasst werden, indem Sie mehr Spalten zu Temp hinzufügen Tabelle und Datentabelle. –

5

Um diesen Code arbeiten zu lassen, ging ich auf die dunkle Seite.

Seit Dapper macht meine Liste in Parameter. Und SQL Server kann viele Parameter nicht verarbeiten. (Ich habe noch nie zuvor zweistellige Parameter benötigt). Ich musste mit Dynamic SQL gehen.

hier also meine Lösung war:

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

Vor jeder die ihre Fackeln und Heugabeln packt, lassen Sie mich erklären.

  • Dieser Code wird auf einem Server ausgeführt, dessen einzige Eingabe ein Datenfeed von einem Mainframe-System ist.
  • Die Liste, die ich dynamisch erstelle, ist eine Liste von Longs/Bigints.
  • Die Longs/Bigints stammen aus einer Identity-Spalte.
  • Ich weiß, das Erstellen von dynamischen SQL ist schlecht Juju, aber in diesem Fall kann ich nicht sehen, wie es zu einem Sicherheitsrisiko führt.

    +2

    [Little Bobby Tables] (https://xkcd.com/327/) sagen, ist G'Day! –

    +3

    @ Pure.Krome vermutlich ist sein 'listOfIds' vom Typ' List 'daher keine Notwendigkeit, die Eingaben zu bereinigen – Zac

    +0

    Wahrscheinlich ... aber Annahmen sind die Wurzel allen Übels. Zweitens, es ist der allgemeine Vorschlag => Erstellen eines SQL-Skript, im laufenden Betrieb und in einer Zeichenfolge ... könnte sehr schlecht enden :) –

    2

    Dapper Anforderung der Liste des Objekt mit Parametern als Eigenschaft so in obigem Fall eine Liste von Objekt-ID als Eigenschaft aufweisen arbeiten.

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

    Dies wird funktionieren.

    Verwandte Themen