Pracuję więc nad bazą danych, którą dodam do moich przyszłych projektów jako pewnego rodzaju db wspierający, ale mam trochę problem, zwłaszcza dzienniki.Sql Server 2008 Tuning z dużymi transakcjami (700k + wiersze/transakcja)
Baza danych zasadniczo musi być aktualizowana raz w miesiącu. Główna tabela musi zostać wyczyszczona, a następnie uzupełniona z pliku CSV. Problem polega na tym, że serwer Sql wygeneruje dla niego dziennik, który jest MEGA duży. Udało mi się go wypełnić raz, ale chciałem przetestować cały proces, oczyszczając go, a następnie uzupełniając.
Wtedy pojawia się błąd, że plik dziennika jest wypełniony. Przeskakuje z 88 MB (po zmniejszeniu poprzez plan konserwacji) do 248 MB, a następnie zatrzymuje cały proces i nigdy się nie kończy.
Ograniczam jego wzrost do 256 MB, zwiększając o 16 MB, dlatego nie udało się, ale w rzeczywistości nie potrzebuję go do logowania w ogóle. Czy istnieje sposób na całkowite pominięcie rejestrowania każdego zapytania w bazie danych?
Dzięki za wszelkie odpowiedzi z góry!
EDYTOWANIE: Zgodnie z sugestiami @ mattmc3 zaimplementowałem SqlBulkCopy dla całej procedury. Działa AMAZING, z tym, że moja pętla w jakiś sposób zawiesza się na ostatnim pozostałym fragmencie, który musi zostać wstawiony. Nie jestem zbyt pewny, gdzie idę źle, cholera, nawet nie wiem, czy to jest odpowiednia pętla, więc byłbym wdzięczny za pomoc.
Wiem, że jest to problem z ostatnimi wywołaniami GetDataTable lub SetSqlBulkCopy. Próbuję wstawić 788189 wiersze, 788000 wejść i pozostałe 189 są upaść ...
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/KOD KOŃCOWA: więc aplikacja jest już gotowy i działa niesamowite, i dość szybki! @ Mattmc3, dzięki za pomoc! Oto ostateczny kod dla każdego, komu może się przydać:
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);
};
}
Kilka sugestii, jeśli chcesz przyspieszyć to jeszcze bardziej. 1.) Zamiast robienia Reader.ReadToEnd(), wykonaj pętlę i rób Reader.ReadLine() po jednej linii na raz. Zajmie to mniej pamięci. 2.) Jeśli nikt nie będzie mieć dostępu do twojego stołu podczas ładowania, użyj opcji 'SqlBulkCopyOptions.TableLock'. 3.) Aby zaoszczędzić trochę kodu, obiekt SqlBulkCopy zawiera mapowania kolumn, jeśli nazwy kolumn są takie same, jak w tabeli docelowej, a ponieważ obsługuje się fragmentację, nie ma powodu, aby ustawić .BatchSize albo. Szczęśliwe kodowanie! – mattmc3
Na temat przekierowywania kolumn będzie działać, jeśli: 'DBTable = {Id (PK, IDENTITY), A, B, C, D}', ale 'DataTable = {A, B, C, D}'? Myślę, że to sprawiało mi kłopoty, dlatego je wyszczególniłem, ale znowu mogłem to jakoś skręcić ... – Gup3rSuR4c
Cóż, gotowe! Zaimplementowałem wszystko, co poleciłeś i działa NIESAMOWITE! Pamięć została przecięta na pół do ~ 85 MB, a cała operacja trwa około 45 sekund. I wymyśliłem powyższe kolumny, miałem rację, ale właśnie dodałem symbol zastępczy dla "Id" i zadziałało. 'DZIĘKUJĘ ZA POMAGANIE MNIE W TEJ I NAUCZANIE MNIE O RZECZY NIGDY NIE ZNAJDOWAŁO !!!' – Gup3rSuR4c