Quindi, sto lavorando a un database che aggiungerò ai miei progetti futuri come una sorta di db di supporto, ma sto avendo un po 'di problema con esso, in particolare i registri.Sql Server 2008 Ottimizzazione con transazioni di grandi dimensioni (700k + righe/transazione)
Il database deve essere aggiornato una volta al mese. La tabella principale deve essere eliminata e quindi ricaricata da un file CSV. Il problema è che Sql Server genererà un log che è MEGA grande. Ho avuto successo nel riempirlo una volta, ma volevo testare l'intero processo eliminandolo e quindi ricaricandolo.
Ecco quando viene visualizzato un messaggio di errore relativo al completamento del file di registro. Salta da 88 MB (dopo il restringimento tramite il piano di manutenzione) a 248 MB e quindi interrompe completamente il processo e non viene mai completato.
Ho limitato la crescita a 256 MB, con un incremento di 16 MB, motivo per cui non è riuscito, ma in realtà non ho bisogno di registrare nulla. C'è un modo per bypassare completamente la registrazione su qualsiasi query eseguita sul database?
Grazie per eventuali risposte in anticipo!
MODIFICA: Per i suggerimenti di @ mattmc3 ho implementato SqlBulkCopy per l'intera procedura. Funziona INCREDIBILE, ad eccezione del fatto che il mio ciclo si arresta in qualche modo sull'ultimo chunk rimasto che deve essere inserito. Non sono troppo sicuro di dove sto andando male, diamine non so nemmeno se questo è un ciclo appropriato, quindi apprezzerei un po 'di aiuto su di esso.
So che si tratta di un problema con le ultime chiamate GetDataTable o SetSqlBulkCopy. Sto cercando di inserire 788189 righe, 788.000 entrare e il restante 189 si infrangono ...
string[] Rows;
using (StreamReader Reader = new StreamReader("C:/?.csv")) {
Rows = Reader.ReadToEnd().TrimEnd().Split(new char[1] {
'\n'
}, StringSplitOptions.RemoveEmptyEntries);
};
int RowsInserted = 0;
using (SqlConnection Connection = new SqlConnection("")) {
Connection.Open();
DataTable Table = null;
while ((RowsInserted < Rows.Length) && ((Rows.Length - RowsInserted) >= 1000)) {
Table = GetDataTable(Rows.Skip(RowsInserted).Take(1000).ToArray());
SetSqlBulkCopy(Table, Connection);
RowsInserted += 1000;
};
Table = GetDataTable(Rows.Skip(RowsInserted).ToArray());
SetSqlBulkCopy(Table, Connection);
Connection.Close();
};
static DataTable GetDataTable(
string[] Rows) {
using (DataTable Table = new DataTable()) {
Table.Columns.Add(new DataColumn("A"));
Table.Columns.Add(new DataColumn("B"));
Table.Columns.Add(new DataColumn("C"));
Table.Columns.Add(new DataColumn("D"));
for (short a = 0, b = (short)Rows.Length; a < b; a++) {
string[] Columns = Rows[a].Split(new char[1] {
','
}, StringSplitOptions.RemoveEmptyEntries);
DataRow Row = Table.NewRow();
Row["A"] = Columns[0];
Row["B"] = Columns[1];
Row["C"] = Columns[2];
Row["D"] = Columns[3];
Table.Rows.Add(Row);
};
return (Table);
};
}
static void SetSqlBulkCopy(
DataTable Table,
SqlConnection Connection) {
using (SqlBulkCopy SqlBulkCopy = new SqlBulkCopy(Connection)) {
SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("A", "A"));
SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("B", "B"));
SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("C", "C"));
SqlBulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping("D", "D"));
SqlBulkCopy.BatchSize = Table.Rows.Count;
SqlBulkCopy.DestinationTableName = "E";
SqlBulkCopy.WriteToServer(Table);
};
}
EDIT/codice finale: Così l'App è ora finito e incredibili opere, e molto veloce! @ mattmc3, grazie per tutto l'aiuto! Ecco il codice finale per chiunque lo trovi utile:
List<string> Rows = new List<string>();
using (StreamReader Reader = new StreamReader(@"?.csv")) {
string Line = string.Empty;
while (!String.IsNullOrWhiteSpace(Line = Reader.ReadLine())) {
Rows.Add(Line);
};
};
if (Rows.Count > 0) {
int RowsInserted = 0;
DataTable Table = new DataTable();
Table.Columns.Add(new DataColumn("Id"));
Table.Columns.Add(new DataColumn("A"));
while ((RowsInserted < Rows.Count) && ((Rows.Count - RowsInserted) >= 1000)) {
Table = GetDataTable(Rows.Skip(RowsInserted).Take(1000).ToList(), Table);
PerformSqlBulkCopy(Table);
RowsInserted += 1000;
Table.Clear();
};
Table = GetDataTable(Rows.Skip(RowsInserted).ToList(), Table);
PerformSqlBulkCopy(Table);
};
static DataTable GetDataTable(
List<string> Rows,
DataTable Table) {
for (short a = 0, b = (short)Rows.Count; a < b; a++) {
string[] Columns = Rows[a].Split(new char[1] {
','
}, StringSplitOptions.RemoveEmptyEntries);
DataRow Row = Table.NewRow();
Row["A"] = "";
Table.Rows.Add(Row);
};
return (Table);
}
static void PerformSqlBulkCopy(
DataTable Table) {
using (SqlBulkCopy SqlBulkCopy = new SqlBulkCopy(@"", SqlBulkCopyOptions.TableLock)) {
SqlBulkCopy.BatchSize = Table.Rows.Count;
SqlBulkCopy.DestinationTableName = "";
SqlBulkCopy.WriteToServer(Table);
};
}
Alcuni suggerimenti se si desidera accelerare ulteriormente. 1.) Invece di fare Reader.ReadToEnd(), creare un ciclo e fare Reader.ReadLine() una riga alla volta. Ci vorrà meno memoria. 2.) Se nessuno accederà al tuo tavolo durante il tempo in cui lo stai caricando, usa l'opzione 'SqlBulkCopyOptions.TableLock'. 3.Solo per risparmiare un po 'di codice, l'oggetto SqlBulkCopy deduce i tuoi mapping di colonne se assegni alle colonne lo stesso valore della tabella di destinazione, e dal momento che stai gestendo il chunking da solo, non c'è motivo di impostare anche .BatchSize. Buona programmazione! – mattmc3
L'argomento di inferire le colonne funzionerà se: 'DBTable = {Id (PK, IDENTITY), A, B, C, D}', ma 'DataTable = {A, B, C, D}'? Penso che mi stessero dando problemi, ecco perché li ho specificati, ma poi di nuovo, avrei potuto rovinarlo in qualche modo ... – Gup3rSuR4c
Bene, è fatta! Ho implementato tutto ciò che hai consigliato e funziona INCREDIBILE! La memoria è stata tagliata a metà a ~ 85 MB e l'intera operazione richiede circa 45 secondi. E ho scoperto le colonne sopra, avevo ragione, ma ho appena aggiunto un segnaposto per l'ID e ha funzionato. "GRAZIE PER AVERLO AIUTO A QUESTO E PER INSEGNARMI SULLE COSE CHE NON HO MAI SAPUTO !!!" – Gup3rSuR4c