2017-02-21 15 views
1

У меня есть веб-сайт, который позволяет пользователям загружать данные с использованием определенных критериев поиска (страна и даты) в файл CSV. Они выбирают всю информацию из выпадающего списка и JQuery datepicker.Динамически создавать CSV-файл, используя оператор select в C#

Экспорт прекрасно работает для небольших наборов данных, но как только вы пытаетесь загрузить и загружать 10000 строк данных, это занимает очень много времени и может даже превышать тайм-аут!

Я пробовал разные способы сделать это, но я хотел бы придерживаться этого метода из-за ограничений по времени в этом проекте.

Мой код выглядит следующим образом:

 using (SqlConnection con = new SqlConnection(cs)) 
     { 

      if (country.Contains("GB")) 
      { 
       using (SqlCommand cmd = new SqlCommand("SELECT * from " + logData + " where country in ('GB') and close_date between '" + fromDate + "' and '" + toDate + "'")) 
       { 
        using (SqlDataAdapter sda = new SqlDataAdapter()) 
        { 
         cmd.Connection = con; 
         sda.SelectCommand = cmd; 
         using (DataTable dt = new DataTable()) 
         { 
          sda.Fill(dt); 

          //Build the CSV file data as a Comma separated string. 
          string csv = string.Empty; 

          foreach (DataColumn column in dt.Columns) 
          { 
           //Add the Header row for CSV file. 
           csv += column.ColumnName + ','; 
          } 
          //Console.Write(cmd); 
          //Add new line. 
          csv += "\r\n"; 

          foreach (DataRow row in dt.Rows) 
          { 
           foreach (DataColumn column in dt.Columns) 
           { 
            //Add the Data rows. 
            //Response.Write(row[column.ColumnName].ToString().Replace(",", ";") + ','); 
             csv += row[column.ColumnName].ToString().Replace(",", ";") + ','; 
           } 

           //Add new line. 
           csv += "\r\n"; 
          } 

          //Download the CSV file. 
          Response.Clear(); 
          Response.Buffer = true; 
          Response.AddHeader("content-disposition", "attachment;filename=data.csv"); 
          Response.Charset = ""; 
          Response.ContentType = "application/text"; 
          Response.Output.Write(csv); 
          Response.Flush(); 
          Response.End(); 
         } 
        } 
       } 


      } 

Response.Write (. Строка [column.ColumnName] .ToString() Заменить ("", ";") + '');

csv + = строка [column.ColumnName] .ToString(). Заменить (",", ";") + ',';

Если я использую Response.Write ..., файл загрузки НАМНОГО быстрее, но данные все на одной строке и не включает заголовки. CSV + = строка ... гораздо медленнее, а иногда раз из

Как разделить данные на несколько строк, если я должен был использовать response.write и включают в себя заголовки?

Реальный SQL запрос занимает 2 секунды, чтобы запустить и производит 12231 записей

+0

Использовать строковый построитель вроде этого ...> StringBuilder SB = new StringBuilder(); ... SB.Append (строка [column.ColumnName] .ToString(). Заменить (",", ";")) ; Sb.append (''); ... строковый построитель намного быстрее –

ответ

1

Похоже, вы пытаетесь провести весь набор результатов (от SELECT) в ОЗУ дважды. Не забывайте, что точка SQL, в основном, позволяет работать с наборами данных, которые больше, чем у любой имеющейся у вас RAM. Это не значит, что вы должны это делать, но это означает, что вы должны думать «подряд за раз» при разработке своего программного обеспечения.

В любом случае, вы загружаете весь свой набор результатов в ОЗУ дважды.

Как только вы используете SqlDataAdapter, а не SqlDataReader для извлечения данных. SqlDataReader вытягивает данные по строке за раз.

Опять же, потому что вы пытаетесь вывести весь ваш результат в одну текстовую строку. Это плохо работает (а), потому что требуется много ОЗУ и (b), потому что str = str+whatever должен скопировать строку, стереть старую и сохранить новую. Таким образом,

string str = null; 
foreach (item in someLargeCollection) str = str + item; 

работает в O (n-squared) времени. Когда n (размер коллекции) больше, чем несколько сотен элементов, это выглядит как тайм-аут.

Таким образом, быстрое решение:

 foreach (DataRow row in dt.Rows) 
    { 
     foreach (DataColumn column in dt.Columns) 
     { 
      csv += row[column.ColumnName].ToString().Replace(",", ";") + ','; 
     } 
     csv += "\r\n"; 
     Response.Write(csv); 
     csv = null; 
    } 

Это выписывает каждую строку, сохраняя CSV становится слишком большой, и решает вторую проблему.

StringBuilder исправить ... правильно строить строки:

 foreach (DataRow row in dt.Rows) 
    { 
     StringBuilder csv = new StringBuilder(); 
     foreach (DataColumn column in dt.Columns) 
     { 
      csv.Append(row[column.ColumnName].ToString().Replace(",", ";") + ','); 
     } 
     csv.AppendLine(); 
     Response.Write(csv.ToString()); 
    } 

StringBuilder поражения (п-квадрат) проблему вывода при создании текстовых строк.

Наконец, вы должны найти класс SqlDataReader.

+0

Большое вам спасибо, я понимаю, почему это так долго. Блестящее объяснение, и код работал! :) – akb29

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

  • Нет связанных вопросов^_^