2013-02-27 7 views
7

Ich muss eine große Tabelle mit über 270 Update-Felder aktualisieren.Aktualisieren Sie große Tabelle (viele Spalten). C#. NET

Ich bin relativ neu zu .NET und muss beraten, was ist besser in diesem Fall zu verwenden: SqlCommand, eine Art Memory-Mapped-Tabelle oder DataSet oder vielleicht existiert eine Art von automatisch generierten Objekten mit Metadaten aus DB? Bitte helfen Sie.

Grund: Ich habe eine alte große Delphi7-Anwendung, von der ein Teil für das Anhören von Socket einige Pakete verantwortlich ist, die zu großen Strukturen gemarshallt werden und im letzten Schritt in DB gespeichert werden. Jetzt portiere ich diesen Teil auf den neuen C# Service und zumindest muss ich die gleiche Logik beibehalten. Das Problem ist, dass die Struktur BIG (über 220 Felder) ist und Tabellen, in denen es gespeichert ist, haben fast 300 Felder. Aus meiner Struktur von 220 Feldern werden weitere ~ 50 Felder abgezogen/berechnet und alle sollten in DB aktualisiert werden. Actual Delphi-Code ist hässlich Ameise es über mehrere Jahre wie Tisch wuchs selbst, etwa so:

'UPDATE TABLE_NAME ' + 
    ' MSG_TYPE = ' + IntToStr(integer(RecvSruct.MSG_TYPE)) + ' ' + 
    ' ,SomeFLOATfield = ' + FloatToStr(RecvSruct.SomeFLOATfield) + ' ' + 
    ... //and other over 270 fileds here 
'WHERE ID = ' + IntToStr(obj.ID) 

keine jede dynamische SQL, etc .. Eigentlich kann ich nicht DB-Struktur ändern .. so dass ich spielen muss nur in Code und ich bin mir nicht sicher, ob es richtig ist, Code zu übersetzen. Die Tabelle wird für einige Berichte und Statistiken verwendet. Einige der berechneten/abgeleiteten Felder müssen mit einigen Konstanten im Quellcode umgehen.

verwendet dev-Tools: MS SQL Server 2000, C# .NET2.0, VS2008

+2

Warum verwenden Sie nicht Stored Procedure? Es wird eine verdammt viel einfacher als das sein. –

+0

SqlCommand. Du willst das alles serverseitig. – Stu

+0

Können Sie der Datenbank eine neue gespeicherte Prozedur hinzufügen? – granadaCoder

Antwort

2

Die einfachste Lösung gilt auch hier, weil die Art und Weise ole db Arbeiten mit Strings ist. Um also 270, 500, 1000 Parameter zu übergeben, übergebe ich nur eine einzige Zeichenkette, eine Zeichenkette mit 270 Parametern liegt wahrscheinlich unter 2kB ... was in modernen Computern ... die 1 nicht überträgt ... nicht eine Leistungseinbuße haben. Es gibt eine XML-Lösung hier, aber das sind nur Äpfel und Orangen, Sie übergeben immer noch die Zeichenfolge, es würde jedoch zusätzlichen Code benötigen, um die XML zu behandeln. So ... Ihre Architektur sollte folgendermaßen aussehen:

  1. gespeicherte Prozedur auf SQL Server mit 270 Eingangsparameter:

    Create Procedure sp_Example1 
    (@param1 [type], @param2 [type], @param3 [type], etc...) 
    AS 
    BEGIN 
    [SQL statements] 
    END 
    
  2. Ein Befehlsobjekt mit 270 Parameter:

    SqlCommand cmd = new SqlCommand("sp_Example1", [sqlconnectionstring]); 
    cmd.Parameters.Add(New SqlParameter("@param1", param1.value)); 
    cmd.Parameters.Add(New SqlParameter("@param2", param2.value)); 
    cmd.Parameters.Add(New SqlParameter("@param3", param3.value)); 
    

Denken Sie daran, Sie machen immer noch eine ziemlich intensive Operation, aber Ihre Benchmark sollte die alte Anwendung sein. Wenn es ein bisschen schlechter ist, würde ich mich nicht darum kümmern, da das Framework mehr Rechenaufwand erfordert.

Ich habe keine Ahnung, warum es nicht den Code formatiert ...

+0

Mit SQL Server, ADO.NET würde ich eine Option, also warum OLE DB verwenden? –

+0

@ Syn123, Was meinst du "die Art, wie Ole db arbeitet, ist mit Strings"? Meinst du, dass alle Parameterwerte als Strings übergeben und automatisch rotiert werden? Überprüfen Sie bitte auch diese Frage http://stackoverflow.com/questions/15135204/sql-server-why-field-value-of-almost-any-type-may-be-treated-as-quoted-string – ALZ

+0

SQL-Server-Verbindung verwendet immer noch ole db Ich glaube, es ist nur die Version von Microsoft. Lesen Sie den Unicode-Abschnitt von http://msdn.microsoft.com/en-us/library/ms810892.aspx. Ole DB-Provider (ADO.NET) verwenden den SQL-Port, um Zeichenfolgendaten im Klartext zwischen dem SQL-Server und der Anwendung zu senden. – RandomUs1r

1

Ok. Da Sie eine neue gespeicherte Prozedur hinzufügen können, würde ich vorschlagen, alle Werte zu packen und sie als XML an Ihre gespeicherte Prozedur zu senden.

Sie können ein bisschen Beispiel finden Sie hier: http://granadacoder.wordpress.com/2009/01/27/bulk-insert-example-using-an-idatareader-to-strong-dataset-to-sql-server-xml/

Die gute Nachricht, dass Beispiel, das ich habe, ist älter und kodiert SQL Server 2000 (mit OPENXML).

..

Dies wäre besser als das Senden nach unten 300 Parameter an eine gespeicherte Prozedur, IMHO.

Der andere Vorteil, wenn Sie mehr als 1 Reihe Daten haben, können Sie das auch versenden.

......

Der "Kern" davon:

Erstens können Sie die 2000 "Pubs" Datenbank hier:

http://www.microsoft.com/en-us/download/details.aspx?id=23654

Nun ist diese hinzufügen Stored Procedure:

/* USP */

DROP PROCEDURE dbo.uspTitleUpsert 
GO 





CREATE PROCEDURE dbo.uspTitleUpsert (
    @xml_doc TEXT , 
    @numberRowsAffected int output --return 
) 

AS 

SET NOCOUNT ON 

DECLARE @hdoc INT -- handle to XML doc 

DECLARE @errorTracker int -- used to "remember" the @@ERROR 

DECLARE @updateRowCount int 
DECLARE @insertRowCount int 


--Create an internal representation of the XML document.  
EXEC sp_xml_preparedocument @hdoc OUTPUT, @XML_Doc  



-- build a table (variable table) to store the xml-based result set 
DECLARE @titleupdate TABLE ( 
    identityid int IDENTITY (1,1) , 

title_id varchar(6) , 
title varchar(80) , 
type varchar(32) , 
pub_id varchar(32) , 
price money , 
advance money , 
royalty varchar(32) , 
ytd_sales varchar(32) , 
notes TEXT , 
pubdate datetime 
) 




--the next call will take the info IN the @hdoc(with is the holder for @xml_doc), and put it IN a variableTable 
INSERT @titleupdate 
    (
     title_id , 
     title , 
     type , 
     pub_id , 
     price , 
     advance , 
     royalty , 
     ytd_sales , 
     notes , 
     pubdate 
    ) 
SELECT 
    title_id , 
    title , 
    type , 
    pub_id , 
    price , 
    advance , 
    royalty , 
    ytd_sales , 
    notes , 
    getdate() /*dbo.udf_convert_xml_date_to_datetime (pubdate)*/ 
FROM 
    -- use the correct XPath .. the second arg ("2" here) distinquishes 
    -- between textnode or an attribute, most times with 
    --.NET typed datasets, its a "2" 
    --This xpath MUST match the syntax of the DataSet 
OPENXML (@hdoc, '/TitlesDS/Titles', 2) WITH ( 

    title_id varchar(6) , 
    title varchar(80) , 
    type varchar(32) , 
    pub_id varchar(32) , 
    price money , 
    advance money , 
    royalty varchar(32) , 
    ytd_sales varchar(32) , 
    notes TEXT , 
    pubdate varchar(32) 

) 


EXEC sp_xml_removedocument @hdoc 



select * from @titleupdate 



SET NOCOUNT OFF 




Update 
    dbo.titles 
set 
    title = vart.title , 
    type = vart.type , 
    pub_id = vart.pub_id , 
    price = vart.price , 
    advance = vart.advance , 
    royalty = vart.royalty , 
    ytd_sales = vart.ytd_sales , 
    notes = vart.notes , 
    pubdate = vart.pubdate 
FROM 
    @titleupdate vart , dbo.titles realTable 
WHERE 
    (rtrim(upper(realTable.title_id))) = ltrim(rtrim(upper(vart.title_id))) 
    and 
    exists 
    (
     select null from dbo.titles innerRealTable where (rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(vart.title_id))) 
    ) 


Select @updateRowCount = @@ROWCOUNT 

INSERT INTO dbo.titles 
    (
     title_id , 
     title , 
     type , 
     pub_id , 
     price , 
     advance , 
     royalty , 
     ytd_sales , 
     notes , 
     pubdate 
    ) 
Select 
    title_id , 
    title , 
    type , 
    pub_id , 
    price , 
    advance , 
    royalty , 
    ytd_sales , 
    notes , 
    pubdate 
FROM 
    @titleupdate tu 
WHERE 
    not exists 
    (
     select null from dbo.titles innerRealTable where (rtrim(upper(innerRealTable.title_id))) = ltrim(rtrim(upper(tu.title_id))) 
    ) 

Select @insertRowCount = @@ROWCOUNT 

print '/@insertRowCount/' 
select @insertRowCount 
print '' 

print '/@updateRowCount/' 
select @updateRowCount 
print '' 


select @numberRowsAffected = @insertRowCount + @updateRowCount 



--select * from titles 

SET NOCOUNT OFF 


GO 




--GRANT EXECUTE on dbo.uspTitleUpsert TO pubsuser 



GO 

/* Beispiel für die Verwendung */

EXEC dbo.uspTitleUpsert 
' 
<TitlesDS> 
    <Titles> 
     <title_id>PN3333</title_id> 
     <title>Peanut Cooking</title> 
     <type>trad_cook</type> 
     <pub_id>0877</pub_id> 
     <price>3.33</price> 
     <advance>4444.00</advance> 
     <royalty>1</royalty> 
     <ytd_sales>33</ytd_sales> 
     <notes>Peanut Cooking Notes</notes> 
     <pubdate></pubdate> 
    </Titles> 

    <Titles> 
     <title_id>SSMS4444</title_id> 
     <title>Sql Server Management Studio</title> 
     <type>programming</type> 
     <pub_id>0877</pub_id> 
     <price>13.33</price> 
     <advance>5444.00</advance> 
     <royalty>2</royalty> 
     <ytd_sales>33</ytd_sales> 
     <notes>Sql Server Management Studio Notes</notes> 
     <pubdate></pubdate> 
    </Titles> 

</TitlesDS> 
' 
, 0 
+0

vielen Dank - ich werde diese Möglichkeit analysieren und werde hier mein Ergebnis schreiben. Nochmals vielen Dank dafür, dass dies (OPENXML) für mich noch ein unbekanntes Gebiet ist. Ist es vollständig kompatibel mit SQL Server 2000? – ALZ

+0

Ja, OPENXML ist mit Sql Server 2000 in die TSQL-Funktionalität eingebacken. 2005 und höher ersetzt OPENXML durch eine etwas andere Syntax, aber sie behalten OPENXML für Abwärtskompatibilität bei. Bottomline, OPENXML in Sql Server 2000 ist nicht voo doo, es ist da für Ihre Verwendung. – granadaCoder

0

Simple.data verwenden könnte Ihren Code und Logik vereinfachen (obwohl es .NET 4 erfordert.0)

0
  1. Sie können die Tabellen in neue Tabellen aufgeteilt, dann erstellen Sie Ansichten mit dem gleichen Namen wie die alten Tabellen, die verbindet, Schalter, Guss- und usw., die neuen Tabellen in die alten Strukturen für die umwandeln Berichte.

  2. Wenn Sie Befehle verwenden (wie im von Ihnen geposteten Delphi-Code), verwenden Sie Parameter, um SQL-Injection zu verhindern.

  3. Mit der aktuellen DB-Struktur haben Sie eine aus der Box ORM könnte ermüdend sein, da Sie viele Spalten zu mappen haben. Sie könnten POCO-Klassen als typsicheres Modell erstellen und dann Datennotationen oder benutzerdefinierte Attribute verwenden, um die Zuordnung zu vereinfachen. Anschließend können Sie SQL-Befehle direkt aus den Attributen erstellen.

0

Keine speziellen Kaninchen aus dem Hut .net für diesen Ich habe Angst, zu ziehen.

Kurz von den Komplexitäten um "wissend" nur einige völlig unabhängige Felder haben sich geändert und bauen eine Update-Anweisung nur für sie, Sie sind ausgestopft.

Selbst wenn Sie das wüssten, wäre das besser gespeichert worden, da Blob Ihnen nicht wirklich hilft. Wahrscheinlich auf keinen Fall wahr.

Eine parametrisierte Abfrage oder Stored Procedure würde im Code ein wenig besser aussehen, aber das hätte in Delphi sowieso gemacht werden können.

Keine Möglichkeit, von hier zu sagen, wie es gemacht werden sollte, aber eine Idee, die Kilometerstand haben kann, verbirgt die aktuelle Tabelle von allem außer einer kleinen Reihe von Funktionen.

Zum Beispiel, wenn Sie es umbenennen und dann eine Ansicht mit dem aktuellen Namen erstellen. Keines der Dinge, die lesen und (möglicherweise ein gutes Stück Code, der darauf schreibt) würde es bemerken. Wenn Sie zu dem Punkt gelangen, an dem nur über die Ansicht und einige gespeicherte Prozeduren auf die Rohtabelle zugegriffen wird, können Sie mit dem Hacken der Struktur beginnen.

Ein Code (keine SQL) würde nur einen ORM-Stil zwischen den Anwendungen und der Tabelle einfügen. Das ist eine Entscheidung, die mehr als alles andere auf Ihren Fähigkeiten und der Kombination von Anwendungen basieren sollte.

Sofern Sie nicht alle Anwendungen von der spezifischen Implementierung dieser Tabelle entkoppeln können und sind, polieren Sie einfach Fäkalien. Es hat keinen Sinn, wertvolle Ressourcen dafür auszugeben.

+0

keine Bildfelder sind in dieser Tabelle dargestellt, aber in anderen Fällen/Tabellen muss ich binäre (BLOB) Felder aktualisieren - ist SP nutzlos hier? – ALZ

+0

Sicherlich ein sp könnte sehr nützlich sein, es würde diese Mist-Tabelle aus Ihrer Anwendung verstecken, wo immer Sie es verwendet haben. Wie es ein ORM tun würde, was es nicht tun wird, ist das aktuelle Tischdesign in irgendeiner Weise gut zu machen. –

Verwandte Themen