2017-02-21 90 views
1

我有一個網站,允許用戶使用特定的搜索條件(國家和日期)將數據下載到CSV文件。他們從下拉列表和JQuery日期選擇器中選擇所有信息。使用c語言中的select語句動態創建CSV文件#

導出完美適用於小數據集,但只要您嘗試下載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(); 
         } 
        } 
       } 


      } 

回覆於(。行[column.ColumnName]的ToString()更換( 「」, 「;」)+ '');

csv + = row [column.ColumnName] .ToString()。Replace(「,」,「;」)+',';

如果我使用回覆於 ...,文件下載MUCH快,但數據都在同一行,不包括報頭。 CSV + =行...慢得多,偶爾超時

如何將數據劃分到多個行,如果我是用的Response.Write,包括頭?

實際的SQL查詢需要2秒的運行,併產生12231條記錄

+0

使用像這樣的字符串生成器...> StringBuilder SB = new StringBuilder(); ... SB.Append(row [column.ColumnName] .ToString()。Replace(「,」,「;」)) ; SB.Append( ''); ...字符串生成器要快得多 –

回答

1

它看起來像你試圖在RAM中保存整個結果集(從你的SELECT)兩次。不要忘記,SQL的要點基本上是讓您使用比您擁有的RAM更大的數據集。這並不意味着你必須這樣做,但這確實意味着在設計軟件時你應該​​「一次一排地」思考。

無論如何,您將整個結果集加載到RAM中兩次。

一次因爲您使用SqlDataAdapter而不是SqlDataReader來檢索數據。 SqlDataReader一次拉一行數據。

再一次因爲您試圖將您的整個輸出到一個單一的文本字符串。這很糟糕(a),因爲需要大量的RAM,並且 (b)因爲str = str+whatever必須複製字符串,擦除舊字符串並存儲新字符串。因此,

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

在O(n平方)時間內運行。當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創建文本字符串時擊敗爲O(n平方)的問題。

最後,你應該查看SqlDataReader類。

+0

非常感謝,我明白爲什麼現在這麼長時間。精彩的解釋,代碼工作! :) – akb29