2012-04-19 1 views
10

Ich kodiere, um XML-Dateien zu lesen, um die Datenbank zu aktualisieren. Ich bekomme ungefähr 500 XML-Dateien und möchte sie so schnell wie möglich verarbeiten.Ist es möglich, viele gespeicherte Prozeduren in einem einzigen Vorgang auszuführen?

Alle Datenbankoperationen werden mit gespeicherten Prozeduren ausgeführt.

Es gibt ungefähr 35 verschiedene gespeicherte Prozeduren, die für jede XML-Datei aufgerufen werden.

Am Anfang hatte ich den Code wie diese

var cmd = new SqlCommand("EXEC UpdateTeamStats("+teamId+","+points+")"); 
cmd.CommandType = CommandType.Text; 

geschrieben, aber nachdem sie durch einige Best Practices gehen Habe ich es zu

var cmd = new SqlCommand("UpdateTeamStats"); 
cmd.CommandType = CommandType.StoredProcedure; 
cmd.Parameters.Add("teamId", 21); 
cmd.Parameters.Add("points", 2); 

wegen der hohen Anzahl von gespeicherten Prozeduren aus dem Programm aufgerufen wurde Ich erkannte, dass ich weniger Anrufe tätigen muss, um zu optimieren.

Also ich möchte alle 35 gespeicherten Prozeduren zusammen sammeln und sie in einem Rutsch ausführen.

Die gespeicherten Prozeduren sind unterschiedlich mit verschiedenen Parametern und ich kenne keine Möglichkeit, sie zu sammeln und nach den oben beschriebenen Parameteränderungen zusammen auszuführen.

Ich dachte daran, eine riesige gespeicherte Prozedur und innerhalb dieser gespeicherten Prozedur die anderen 35 aufrufen, aber ich bin nicht sehr gut in SQL und es wird zu unnötiger Komplexität führen.

Ist es möglich, dies vollständig in C# zu tun?

Oder gibt es eine andere bessere Methode die StoredProcedures Schlange zu stehen und laufen sie schnell

+0

Was Sie tun erwarten Sie, dass mitten in der Ausführung ein Fehler aufgetreten ist? Werden alle ausgeführten Prozeduren zurückgesetzt? Oder einfach die restlichen Prozeduren weiter bearbeiten? –

+0

Beachten Sie, dass Ihr Titel "parallel" sagt, aber wenn Sie Ihre Frage lesen, sieht es so aus, als ob Sie nur "als einen Datenbankbefehl" meinen. –

+0

@GeorgeDuckett - Das war meine Bearbeitung. Das Original war "auf einmal". – Oded

Antwort

0

Sie könnten eine CommandQueue erstellen, über die Command pattern und einen Delegaten für den Befehl erstellen, die abbildet, was auch immer Ihre Anforderungen sind für den Anruf zur gespeicherten Prozedur; durch das Aussehen, so etwas wie:

public class CommandQueue 
{ 
    private Connection _connexion = new Connection(); // Set this up somehow. 

    // Other methods to handle the concurrency/ calling/ transaction etc. 

    public Func<string, Dictionary<string, int>, bool> CallStoredProcedure = (procedureName, parameterValueMap) => 
    { 
     cmd.Connection = GetConnexion(); 
     var cmd = new SqlCommand(procedureName); 
     cmd.CommandType = CommandType.StoredProcedure; 

     foreach (var parameterValueMapping in parameterValueMap) 
     { 
     cmd.Parameters.Add(parameterValueMapping.Key, parameterValueMapping.Value); 
     } 

     var success = cmd.ExecuteNonQuery(); 

     return success; 
    } 

    private Connection GetConnexion() 
    { 
     return _connexion; 
    } 
} 

Und dann, Setup die CommandQueue, so dass Sie einen Pool von Threads haben, von dem Sie den Delegierten auf einem neuen Thread aufrufen können, so dass sie parallel ausgeführt werden.

Eigentlich, mit Blick auf die SQLCommand Klasse, können Sie asynchrone Anrufe darauf machen. Sie sollten also in der Lage sein, alle gespeicherten Prozeduren asynchron aufzurufen, einen Delegaten für den Abschluss jedes Vorgangs einzurichten und ihn in eine Transaktion umzuwandeln, sodass Sie ihn bei Bedarf durch einen Aufruf von Cancel() bei jedem Befehl zurücksetzen können. Ich würde wahrscheinlich immer noch eine CommandQueue verwenden, um dies zu abstrahieren, wie ich vorschlagen würde, dass Sie es wahrscheinlich später ändern werden!

Ich denke, ich würde immer noch die gespeicherte Prozedur-Aufruf mit einem Delegaten auf einer CommandQueue kapseln, so dass dies die Details der gespeicherten Proc abstrahiert und macht den Prozess für jedermann leichter zu verstehen und auch einfacher zu pflegen. Es wird viel einfacher, wenn Sie neue gespeicherte Procs hinzufügen oder den Namen oder etwas ändern. Sie können eine statische Liste einrichten, die alle Delegaten enthält, oder eine statische Liste mit den erforderlichen gespeicherten Prozedurdetails, und den Delegaten verwenden, um nur die Parameter zu übergeben.

1

Bitte laden Block Microsoft-Anwendungen Daten aus

http://www.microsoft.com/download/en/details.aspx?id=435

gut, aber wie kann ich es nutzen?

Die Verwendung dieser Wrapper-Klasse ist recht einfach.

DAC DC = new DAC(); 
DC.StoredProcedure = "nProc_InsertOrder"; 
DC.Params.Add("@OrderId", SqlDbType.VarChar, "Order1"); 
DC.Params.Add("@CustomerName", SqlDbType.VarChar, "test"); 
DAC.Commands.Add(DC); 

DC = new DAC(); 
DC.StoredProcedure = "nProc_InsertOrderLineItems"; 
DC.Params.Add("@OrderId", SqlDbType.VarChar, "Order1"); 
DC.Params.Add("@OrderLineId", SqlDbType.VarChar, "A1"); 
DAC.Commands.Add(DC); 

DC = new DAC(); 
DC.StoredProcedure = "nProc_InsertOrderLineItems"; 
DC.Params.Add("@OrderId", SqlDbType.VarChar, "Order1"); 
DC.Params.Add("@OrderLineId", SqlDbType.VarChar, "A2"); 
DAC.Commands.Add(DC); 

DC = new DAC(); 
DC.StoredProcedure = "nProc_CreateBill"; 
DC.Params.Add("@BillDate", SqlDbType.DateTime, DateTime.Now); 
DC.Params.Add("@BillId", SqlDbType.VarChar, "Bill1"); 
DAC.Commands.Add(DC); 
DAC.ExecuteBatch(); 

Wenn die Auftragseinfügung fehlschlägt, sollte die Rechnung nicht erstellt werden. Wenn die Werbebuchungen fehlgeschlagen sind, sollte die Bestellung nicht erstellt werden. Wir erreichen dies in nur wenigen Codezeilen über ADO.Net.

In diesem Beispiel fügen wir bis zum Aufruf von ExecuteBatch nicht die Datensätze ein, sondern bereiten das Objekt für Batch-Aktualisierungen vor.

+0

Woher kommt das DAC-Hauptobjekt - das, das wir für 'DAC.Commands.Add' verwenden? Es kann nicht statisch sein, sonst wäre das nicht threadsicher! Und macht das wirklich, was wir hier wollen - ohne explizite Unterstützung durch die SQL Server-Client-Klassen macht das wirklich nur einen einzigen DB-Umlauf oder wickelt stattdessen alle Befehle in eine Transaktion ein? – Rup

+0

Wir wickeln alle Befehle in einem einzigen Objekt ab und führen sie in einer einzigen offenen Verbindung mit der Transaktion aus. –

1

Die beste Lösung Imo wäre, eine einzige gespeicherte Prozedur mit einem tabellarisch übergebenen Parameter zu schreiben, der eine Liste aller Parameter pro XML-Datei enthält. Dann rufen Sie in diesem gespeicherten Prozess alle anderen gespeicherten Prozeduren für jeden Datensatz im Tabellenwertparameter auf.

Wenn dies nicht in Ordnung ist, dann könnten Sie einen SqlCommand vom Typ text anstelle von Stored Procedure verwenden und einfach den Befehl erstellen, während Sie ihn ausführen und ausführen. Sie können Parameter wie Sie jetzt verwenden oder Sie können einfach dynamische SQL schreiben.

0

persönlich und in meiner Erfahrung ADO.NET verwenden, ich glaube, Sie diese als getrennte Aussagen auch immer die Ausführung mit einem einzigenSqlConnection kein Problem hat.

Dies hat den Vorteil, NETs erstaunliche connection pooling zu nutzen, ermöglicht Ihnen die Arbeit/anpassen/interagieren mit jedem Befehl einzeln und reitet eine gemeinsame Verbindung (reduziert die Höhe der Verbindung Makeln auf eine triviale Menge).

Ich möchte auch die wichtigen der using Klauseln hier betonen, die die ordnungsgemäße Entsorgung der verschiedenen Ressourcen erleichtern.

Zum Beispiel:

using (var conn = new SqlConnection("connection string")) 
{ 
    using (var cmd = new SqlCommand()) 
    { 
     cmd.Connection = conn; 
     cmd.CommandType = CommandType.StoredProcedure; 

     //ready to query 
     conn.Open(); 

     cmd.CommandText = "UpdateTeamStats"; 
     var teamIdParam = new SqlParameter("teamId", 21); 
     var pointsParam = new SqlParameter("points", 2); 

     cmd.Parameters.Add(teamIdParam); 
     cmd.Parameters.Add(pointsParam); 

     cmd.ExecuteNonQuery(); //OR if you're async cmd.ExecuteNonQueryAsync(); 

     //the rest of your executions 

     conn.Close(); 
    } 
} 

Und wenn ich für einen Moment sein solicitous, können Sie eine Bibliothek verwenden, wie meine DbConnect, die die oben reduziert:

using (var db = new DbConnect("connection string")) 
{ 
    db.SetSqlCommand("UpdateTeamStats"); 
    db.AddParameter("teamId", 21); 
    db.AddParameter("points", 2); 

    db.ExecuteNonQuery().Wait(); //OR if youre async await db.ExecuteNonQuery(); 

    db.ClearParameters(); 
    db.SetSqlCommand("some other proc"); 

    //rest of executions 
}