2010-12-30 16 views
8

Sto leggendo un file di foglio di calcolo tramite C# ... e il mio foglio di calcolo ha più di 1000 righe. Ho bisogno di inviare ogni riga di dati alla stored procedure per eseguire alcuni logica lato database e aggiornare i record. Ho bisogno di aiuto per inviare tutte quelle 1000 righe di dati in un singolo round trip per risparmiare tempo. Qual è la tecnica necessaria per raggruppare tutte queste 1000 righe di dati.Per passare alla rinfusa file di dati archiviati Procedura

+0

Si sta utilizzando SQL Server? In caso affermativo, quale versione di SQL Server stai usando? –

+1

1000 non sono molti - sei sicuro di aver bisogno di preoccuparti? È possibile trovare 1000 righe una alla volta, tuttavia non si notano problemi di prestazioni evidenti. Se è più facile farlo uno alla volta, darei una prova prima e vedere cosa succede. –

risposta

20

Supponendo che si stia utilizzando SQL Server 2008 o meglio sono disponibili alcune opzioni. Tutte queste opzioni sono state trattate in grande dettaglio al Tech-Ed 2010 di New Orleans e allo video of the session is available online. Di seguito è riportato un riepilogo delle opzioni presentate.

Opzione # 1 - Inserimento di massa (in realtà non coperto in video)

Questa è una grande opzione se hai solo bisogno di "scaricare" i dati in una tabella e non c'è bisogno di fare molto con i dati tranne che nel database. Questo è anche supportato in ADO.NET utilizzando l'oggetto SqlBulkCopy. Ho anche scritto un lightweight wrapper you can find on CodePlex per fare lavorare con SQL Server e ADO.NET facile

Opzione # 2 - Passa un elenco delimitato

prendere tutti i dati e costruire una grande corda e passare l'intera stringa in una stored procedure. Questo è sorprendentemente veloce ma viene fornito con un sacco di bagagli. È necessario disporre di una funzione di divisione per ottenere i dati e per ottenere le migliori prestazioni è necessario eseguire la divisione con SQL-CLR e che può essere mostrata se non si possiede il database.

Opzione # 3 - Far passare come XML

Questo è quasi identica a Opzione # 2, perché si sta ancora una volta di passaggio in una stringa da gigante verso un parametro. Questo ha anche delle prestazioni ragionevoli, ma ha anche gran parte dello stesso bagaglio che ha l'Opzione # 2 ma senza la funzione split perché Sql Server sa come analizzare XML.

Opzione # 4 - utilizzare una tabella funzione con valori (SQL Server 2008)

Questa opzione è molto fresco e offre le migliori prestazioni. Si inizia creando un tipo di valore in SQL Server di tipo "Tabella", quindi si crea una stored procedure che accetta quel tipo di valore come parametro. In C# è ora possibile creare un SqlCommand e aggiungere un parametro con un tipo di SqlDbType.Structured.

cmd.CommandType = CommandType.StoredProcedure; 
cmd.CommandText = "Test.spTVP"; 
var p = cmd.Parameters.Add("@Values", SqlDbType.Structured); 
p.TypeName = "Test.OrderTableType"; 
p.Value = dataTable; 
cmd.Execute…; 

Quando la stored procedure viene eseguita tutti i dati è disponibile nella variabile di tabella della stored procedure. Può essere usato come qualsiasi altra variabile di tabella, quindi spostare i dati è molto semplice.

Opzione # 5 - Utilizzare un Streaming valori di tabella funzione (SQL Server 2008)

Un po 'più di lavoro, allora l'opzione # 4, perché si deve impostare un iteratore ma si ottiene alcune prestazioni folle fuori perché non è necessario caricare tutti i dati sul client prima di trasferirli nella stored procedure. .NET Runtime invierà effettivamente i dati nel database e l'implementazione della stored procedure è la stessa.

class MyStreamingTvp : IEnumerable<SqlDataRecord> { … 
} 
… 
cmd.CommandType = CommandType.StoredProcedure; 
cmd.CommandText = "Test.spTVP"; 
var p = cmd.Parameters.Add("@Values", SqlDbType.Structured); 
p.TypeName = "Test.OrderTableType"; 
p.Value = new MyStreamingTvp(…); 
cmd.Execute…; 

Tutte queste opzioni sono coperti con grande dettaglio e un po 'di umorismo nel video ho detto all'inizio. È stata una delle mie sessioni preferite al Tech-Ed quest'anno.

+0

+1: Ottime opzioni, spero di poter votare di più – TalentTuner

+0

@Saurabh L'ho fatto per te :-) –

+0

Ciao Ryan, ottima risposta! Solo il collegamento video non funziona più.Puoi per favore postare un nuovo link o conosci ancora il titolo della sessione? I video di sessione devono essere ancora su cannel9 ... – Markus

3

risposta di Ryan è molto accurata e copre le varie opzioni. Per un numero relativamente piccolo di righe (1000-5000 è piuttosto piccolo tutto sommato), vorrei utilizzare ciò che è descritto come opzione # 3, passando XML come parametro di stored procedure. Lo facciamo spesso nel mio negozio e quello che segue è il codice associato:

Sto assumendo che i dati del foglio di calcolo siano semplici e che tu sia già disponibile nel tuo codice come qualcosa di simile a un Elenco che hai creato o un DataTable. Per questo semplice esempio, assumerò che i tuoi dati siano un DataTable per semplicità.

io, come Ryan, sto assumendo anche SQL 2008.

1 - Preparare i dati in C# trasformando i dati in XML che saranno passati alla stored procedure. Questa è solo una stringa di XML. Usiamo un metodo nella nostra classe Base Data. Passa il tuo DataTable e lo convertirà in una semplice stringa XML che puoi passare come parametro alla stored procedure.

public string ConvertToXMLDataString(DataTable table) { 
     StringBuilder XMLString = new StringBuilder(); 
     if (string.IsNullOrEmpty(table.TableName)) 
      table.TableName = "DataTable"; 
     XMLString.AppendFormat("<{0}>", table.TableName); 
     DataColumnCollection tableColumns = table.Columns; 
     foreach (DataRow row in table.Rows) { 
      XMLString.AppendFormat("<RowData>"); 
      foreach (DataColumn column in tableColumns) { 
       XMLString.AppendFormat("<{1}>{0}</{1}>", row[column].ToString(), column.ColumnName); 
      } 
      XMLString.AppendFormat("</RowData>"); 
     } 
     XMLString.AppendFormat("</{0}>", table.TableName); 
     return XMLString.ToString(); 
    } 

2 - ho creato un semplice esempio DataTable che conterrà 1000 righe di dati, tutti gli interi, 10 colonne

DataTable table = new DataTable("DataTable"); 
      for(int i = 1; i < 11; i++){ 
       table.Columns.Add(new DataColumn("Column" + i.ToString())); 
      } 
      int j = 0; 
      for (int i = 0; i < 1000; i++) { 
       DataRow newRow = table.NewRow(); 
       for (int k = 0; k < table.Columns.Count; k++) { 
        newRow[k] = j++; 
       }    
       table.Rows.Add(newRow); 
      } 

Il risultato finale di passare il DataTable a ConvertToXMLDataString è una ben formattata rappresentazione XML del DataTable che può essere passato nella stored procedure e facilmente scelto tra:

<DataTable> 
    <RowData> 
     <Column1>0</Column1> 
     <Column2>1</Column2> 
     <Column3>2</Column3> 
     <Column4>3</Column4> 
     <Column5>4</Column5> 
     <Column6>5</Column6> 
     <Column7>6</Column7> 
     <Column8>7</Column8> 
     <Column9>8</Column9> 
     <Column10>9</Column10> 
    </RowData> 
    <RowData> 
     <Column1>10</Column1> 
     <Column2>11</Column2> 
     <Column3>12</Column3> 
     <Column4>13</Column4> 
     <Column5>14</Column5> 
     <Column6>15</Column6> 
     <Column7>16</Column7> 
     <Column8>17</Column8> 
     <Column9>18</Column9> 
     <Column10>19</Column10> 
    </RowData> 
</DataTable> 

3 - Ora, creare una stored procedure che gestirà che X Stringa di dati ML che è stata passata in esso.

CREATE PROCEDURE [dbo].[pr_Test_ConvertTable] 
@TableData XML 
AS 
BEGIN 
    SET NOCOUNT ON 
    SET ANSI_NULLS ON 
    SET ARITHABORT ON 

    DECLARE @TempTable TABLE (
     Column1 int, Column2 int, Column3 int, Column4 int, Column5 int, 
     Column6 int, Column7 int, Column8 int, Column9 int, Column10 int 
    ) 

    INSERT INTO @TempTable (Column1, Column2, Column3, Column4, Column5, Column6, Column7, Column8, Column9, Column10) 
    SELECT XmlTable.Data.value('(./Column1)[1]','int'), XmlTable.Data.value('(./Column2)[1]','int'), 
    XmlTable.Data.value('(./Column3)[1]','int'), XmlTable.Data.value('(./Column4)[1]','int'), 
    XmlTable.Data.value('(./Column5)[1]','int'), XmlTable.Data.value('(./Column6)[1]','int'), 
    XmlTable.Data.value('(./Column7)[1]','int'), XmlTable.Data.value('(./Column8)[1]','int'), 
    XmlTable.Data.value('(./Column9)[1]','int'), XmlTable.Data.value('(./Column10)[1]','int') 
    FROM @TableData.nodes('//DataTable/RowData') AS XmlTable(Data) 

    SELECT * FROM @TempTable 
END 
GO 

4 - La procedura accetta la variabile XML di @TableData e lo inserisce in una variabile di tabella appena creata denominata @TempTable.

Il passo finale è quello di creare ora la chiamata database con il parametro XML corretto. Chiama l'SP come faresti normalmente, usa solo questo come parametro.

cmd.Parameters.Add("@TableData", SqlDbType.Xml).Value = ConvertToXMLDataString(table); 

Là ce l'hai. Dovresti essere in grado di adattarti di conseguenza per gestire i tuoi dati. Generalmente odio passare DataTable in giro, preferisco piuttosto passare un oggetto o una lista in giro, ma in questa situazione, probabilmente hai già i tuoi dati nel DataTable.

Se si tratta di una cosa fatta una volta sola, o di un tipo non frequente, l'impatto sulle prestazioni che si ottiene in cambio della praticità dell'uso di XML è minimo. Se questo è qualcosa che accade spesso da molti utenti, utilizzare l'approccio più efficiente.

+0

Oh, e non ho mai davvero SELEZIONARE *, che è zoppo. Solo lì per l'esempio. Non farlo. –

Problemi correlati