2016-09-09 2 views
2

Я беру 100 + таблицы из базы данных SQL и записываю все данные в 1 файл. В SQL я запускал сложный запрос для форматирования таблиц в одно представление. В VS я подключаюсь к SQL и выбираю * из представления и используя String Builder для создания файла.C# Строить очень большой текстовый файл из SQL-запроса

Это работает, если я получаю только 5% данных и аварийно завершает работу с исключением памяти, если попытаюсь захватить 100%. У просмотра 10 миллионов записей. Я ищу совет. Благодарю.

string cs4 = ConfigurationManager.ConnectionStrings["example"].ConnectionString; 
StringBuilder sb4 = new StringBuilder(); 
using (SqlConnection con4 = new SqlConnection(cs4)) 
{ 
    string strTQuery = @"SELECT * FROM [dbo].[view]"; 
    SqlDataAdapter da4 = new SqlDataAdapter(strTQuery, con4); 
    DataSet ds4 = new DataSet(); 
    da4.Fill(ds4); 

    ds4.Tables[0].TableName = "Example"; 

    foreach (DataRow exDR in ds4.Tables["Example"].Rows) 
    { 
     sb4.Append(exDR["A"].ToString() + strDelimiter); 
     sb4.Append(exDR["B"].ToString() + strDelimiter); 
     sb4.Append(exDR["C"].ToString() + strDelimiter); 
     sb4.Append(exDR["D"].ToString()); 
     sb4.Append("\r\n"); 
    } 
} 

StreamWriter file4 = new StreamWriter(@"\\Desktop" + todaysDate + ".csv"); 
file4.WriteLine(sb4.ToString()); 
file4.Close(); 
+1

Запись в файл, как вы читаете из результата - вы пытаетесь засунуть все эти данные в строку в памяти, только запись в файл в конце. Я предполагаю, что у вас гораздо меньше памяти, чем у вас есть данные. –

+1

@DStanley - не будет ли DataSet хранить все данные? Jay - Возможно, используя 'SqlDataReader' и делая, как сказал DStanley, и запись в файл по мере чтения будет работать лучше. –

ответ

3

Как уже упоминалось, D Stanley вам нужно писать одновременно с чтением, поэтому все идет прямо на диск и не переходит в память сначала, а затем диск. Что-то вроде этого будет работать.

string cs4 = ConfigurationManager.ConnectionStrings["example"].ConnectionString; 

using (SqlConnection con4 = new SqlConnection(cs4)) 
using(StreamWriter file4 = new StreamWriter(@"\\Desktop" + todaysDate + ".csv")) 
{ 
    string strTQuery = @"SELECT A, B, C, D FROM [dbo].[view]"; 
    var command = new SqlCommand(strTQuery, con4); 
    con4.Open(); 
    var reader = command.ExecuteReader(); 

    while(reader.Read()) 
    { 
     file4.Write(reader.GetString(0) + strDelimiter); 
     file4.Write(reader.GetString(1) + strDelimiter); 
     file4.Write(reader.GetString(2) + strDelimiter); 
     file4.Write(reader.GetString(3)); 
     file4.Write("\r\n"); 
    } 
} 

Вы должны также использовать SqlDataReader вместо DataSet как это указатель вперед движется и получает результаты с каждой итерации.

+0

Спасибо! SqlDataReader был для меня проблемой. Очень ценю всех, кто прокомментировал. – Jay

+0

@Jay - рад, что это помогло. Как только вы почувствуете, что нашли ответ среди опубликованных ответов, отметьте его как таковой, используя галочку рядом с ответом. Вы можете отметить только один опубликованный ответ в качестве ответа на свой вопрос. После того, как вы получите достаточно rep (+15), вы также можете отменить ответы, и это не ограничивается одним ответом. – Igor

-1

Проблема заключается в этой строке:

file4.WriteLine(sb4.ToString()); 

Причина в том, ни один объект в CLR не может быть больше, чем 2 Гб. Ваша строка в этом случае является исключительной большой, и такое поведение даже не требуется (ToString я имею в виду). Чтобы избежать этой проблемы, используйте FileStream для записи ваших данных по мере их получения.

0

Вы пытаетесь сохранить весь файл в памяти во время выполнения, поэтому вы получаете ошибку памяти. Попробуйте сохранить куски файла и выложите файл.

попробовать

string cs4 = ConfigurationManager.ConnectionStrings["example"].ConnectionString; 
      StringBuilder sb4 = new StringBuilder(); 
      using (SqlConnection con4 = new SqlConnection(cs4)) 
      { 
       StreamWriter file4 = new StreamWriter(@"\\Desktop" + todaysDate + ".csv", true); 
       string strTQuery = @"SELECT * FROM [dbo].[view]"; 
       SqlDataAdapter da4 = new SqlDataAdapter(strTQuery, con4); 
       DataSet ds4 = new DataSet(); 
       da4.Fill(ds4); 

       ds4.Tables[0].TableName = "Example"; 

       foreach (DataRow exDR in ds4.Tables["Example"].Rows) 
       { 
        sb4 = new StringBuilder(); 
        sb4.Append(exDR["A"].ToString() + strDelimiter); 
        sb4.Append(exDR["B"].ToString() + strDelimiter); 
        sb4.Append(exDR["C"].ToString() + strDelimiter); 
        sb4.Append(exDR["D"].ToString()); 
        sb4.Append("\r\n"); 

        file4.WriteLine(sb4.ToString()); 
       } 
       file4.Close(); 
      } 
+2

Исправьте меня, если я ошибаюсь, но DataSet попытается сохранить все данные, поэтому проблема с памятью не будет решена при использовании. Использование «SqlDataReader» было бы лучшим выбором. Кроме того, создание нового 'StringBuilder' каждый раз через цикл не кажется лучшим выбором. Возможно, было бы лучше очистить содержимое существующего. –

+0

Да, правильно. Но сама проблема заключается в том, что он пытается хранить все данные в памяти времени выполнения. – Sudet

+0

Я хочу сказать, что просто переключение на StreamWriter не решит проблему. Использование DataSet также будет хранить все данные в памяти. –

Смежные вопросы