【问题标题】:Export Sql data to Excel very slow将Sql数据导出到Excel很慢
【发布时间】:2014-07-30 11:38:08
【问题描述】:

我正在将 Sql 数据导出到 Excel。我目前使用的代码是:

    DataTable dt = new DataTable();
            // Create sql connection string
            string conString = "Data Source=DELL\\SQLSERVER1;Trusted_Connection=True;DATABASE=Zelen;CONNECTION RESET=FALSE";

            SqlConnection sqlCon = new SqlConnection(conString);
            sqlCon.Open();


            SqlDataAdapter da = new SqlDataAdapter("select LocalSKU,ItemName, QOH,Price,Discontinued,CAST(Barcode As varchar(25)) As Barcode,Integer2,Integer3,ISNULL(SalePrice,0.0000)AS SalePrice,SaleOn,ISNULL(Price2,0.0000)AS Price2 from dbo.Inventory", sqlCon);

            System.Data.DataTable dtMainSQLData = new System.Data.DataTable();

            da.Fill(dtMainSQLData);
            DataColumnCollection dcCollection = dtMainSQLData.Columns;

            // Export Data into EXCEL Sheet
            Microsoft.Office.Interop.Excel.ApplicationClass ExcelApp = new Microsoft.Office.Interop.Excel.ApplicationClass();
            ExcelApp.Application.Workbooks.Add(Type.Missing);



            int i = 1;
            int j = 1;
            int s = 1;
            //header row
            foreach (DataColumn col in dtMainSQLData.Columns)
            {
                ExcelApp.Cells[i, j] = col.ColumnName;
                j++;

                ExcelApp.Rows.AutoFit();
                ExcelApp.Columns.AutoFit();
            }

            i++;

            //data rows
            foreach (DataRow row in dtMainSQLData.Rows)
            {
                for (int k = 1; k < dtMainSQLData.Columns.Count + 1; k++)
                {
                    ExcelApp.Cells[i, k] = "'" + row[k - 1].ToString();
                }

                i++;
                s++;
                Console.Write(s);
                Console.Write("\n\r");

                ExcelApp.Columns.AutoFit();
                ExcelApp.Rows.AutoFit();
            }

            var b = Environment.CurrentDirectory + @"\Sheet1.xlsx";
            ExcelApp.ActiveWorkbook.SaveCopyAs(b);

            ExcelApp.ActiveWorkbook.Saved = true;
            ExcelApp.Quit();

            Console.WriteLine(".xlsx file Exported succssessfully.");

在我的 sql 数据库中需要 70000 行。我在控制台应用程序中运行此脚本。 导出到excel文件需要一个多小时。

如何使用它来更快地导出它?

示例将不胜感激。

【问题讨论】:

  • 这就是 excel coms 的本质。我不相信你能加快速度。
  • 另一种方法是使用 OleDb 将 Excel 工作表视为数据表。 stackoverflow.com/questions/11312661/…stackoverflow.com/questions/11208255/…
  • 我建议导出为 CSV 而不是 excel。它应该是闪电般的速度,并且仍然很容易被 excel 支持。
  • 最近有一个类似的问题(读取值)-据说它与逐个单元格的操作有关...如果您可以改为范围,它可能会加快起来。
  • @bdimag cmets 触发了内存,一次执行一行而不是逐个单元格确实更快。此外,没有理由在每个单元格上自动调整列。摆脱那些电话,并在最后做一次。

标签: c# sql-server-2008-r2 export export-to-excel


【解决方案1】:

如果您将数据保存为 CSV 共振峰,您可以将其加载到 Excel 中,这是我从代码项目站点 http://www.codeproject.com/Tips/665519/Writing-a-DataTable-to-a-CSV-file 修改的一些代码

public class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        DataTable  dt = new DataTable();
        // Create Connection object
        using (SqlConnection conn = new SqlConnection(@"<Your Connection String>"))
        {
            // Create Command object
            conn.Open();
            using (SqlCommand cmd = new SqlCommand("SELECT * FROM <Your Table>", conn))
            {
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    try
                    {
                        dt.Load(reader);

                        using (StreamWriter writer = new StreamWriter("C:\\Temp\\dump.csv"))
                        {
                            DataConvert.ToCSV(dt, writer, false);
                        }
                    }
                    catch (Exception)
                    {

                        throw;
                    }
                }
            }
        }

        // Stop timing
        stopwatch.Stop();

        // Write result
        Console.WriteLine("Time elapsed: {0}",
            stopwatch.Elapsed);
        Console.ReadKey();
    }
}


public static class DataConvert
{
    public static void ToCSV(DataTable sourceTable, TextWriter writer, bool includeHeaders)
    {
        if (includeHeaders)
        {
            List<string> headerValues = new List<string>();
            foreach (DataColumn column in sourceTable.Columns)
            {
                headerValues.Add(QuoteValue(column.ColumnName));
            }

            writer.WriteLine(String.Join(",", headerValues.ToArray()));
        }

        string[] items = null;
        foreach (DataRow row in sourceTable.Rows)
        {
            items = row.ItemArray.Select(o => QuoteValue(o.ToString())).ToArray();
            writer.WriteLine(String.Join(",", items));
        }

        writer.Flush();
    }

    private static string QuoteValue(string value)
    {
        return String.Concat("\"", value.Replace("\"", "\"\""), "\"");
    }
} 

}

在我的电脑上处理 100 万条记录需要 30 秒...

【讨论】:

  • @jiverson 代码非常高效,在 60 秒内处理了 100 万条记录(3 列)。只是对OP的说明,您仍然可以通过调用Worksheet对象的SaveAs()函数将数据保存为xlsx文件[ws.SaveAs("Sheet1.xlsx");]
  • 我刚刚在代码项目网站codeproject.com/Articles/371203/… 上找到了这个。它使用 OpenXML 而不是 Interop,因此可以在没有安装 MS Office 的系统上运行。
【解决方案2】:

选项 1:

看到这个answer。使用名为 ClosedXML 的库将数据写入 Excel。

选项 2:

为所有数据获取足够大的范围并将值设置为等于二维范围。在没有另一个引用另一个库的情况下,这工作得非常快。我尝试了 70000 条记录。

// Get an excel instance
Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();

// Get a workbook
Workbook wb = excel.Workbooks.Add();

// Get a worksheet
Worksheet ws = wb.Worksheets.Add();
ws.Name = "Test Export";

// Add column names to the first row
int col = 1;
foreach (DataColumn c in table.Columns) {
    ws.Cells[1, col] = c.ColumnName;
    col++;
}

// Create a 2D array with the data from the table
int i = 0;
string[,] data = new string[table.Rows.Count, table.Columns.Count];
foreach (DataRow row in table.Rows) {                
    int j = 0;
    foreach (DataColumn c in table.Columns) {
        data[i,j] = row[c].ToString();
        j++;
    }
    i++;            
}                   

// Set the range value to the 2D array
ws.Range[ws.Cells[2, 1], ws.Cells[table.Rows.Count + 1, table.Columns.Count]].value = data;

// Auto fit columns and rows, show excel, save.. etc
excel.Columns.AutoFit();
excel.Rows.AutoFit();
excel.Visible = true;

编辑:这个版本在我的机器上导出了一百万条记录大约需要一分钟。此示例使用 Excel 互操作并将行分成 100,000 个块。

// Start a stopwatch to time the process
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();

// Check if there are rows to process
if (table != null && table.Rows.Count > 0) {

    // Determine the number of chunks
    int chunkSize = 100000;
    double chunkCountD = (double)table.Rows.Count / (double)chunkSize;
    int chunkCount = table.Rows.Count / chunkSize;
    chunkCount = chunkCountD > chunkCount ? chunkCount + 1 : chunkCount;

    // Instantiate excel
    Microsoft.Office.Interop.Excel.Application excel = new Microsoft.Office.Interop.Excel.Application();

    // Get a workbook
    Workbook wb = excel.Workbooks.Add();

    // Get a worksheet
    Worksheet ws = wb.Worksheets.Add();
    ws.Name = "Test Export";

    // Add column names to excel
    int col = 1;                
    foreach (DataColumn c in table.Columns) {
        ws.Cells[1, col] = c.ColumnName;
        col++;
    }

    // Build 2D array
    int i = 0;
    string[,] data = new string[table.Rows.Count, table.Columns.Count];
    foreach (DataRow row in table.Rows) {
        int j = 0;
        foreach (DataColumn c in table.Columns) {
            data[i, j] = row[c].ToString();
            j++;
        }
        i++;
    }

    int processed = 0;
    int data2DLength = data.GetLength(1);
    for (int chunk = 1; chunk <= chunkCount; chunk++) {
        if (table.Rows.Count - processed < chunkSize) chunkSize = table.Rows.Count - processed;            
        string[,] chunkData = new string[chunkSize, data2DLength];
        int l = 0;
        for (int k = processed; k < chunkSize + processed; k++) {
            for (int m = 0; m < data2DLength; m++) {
                chunkData[l,m] = table.Rows[k][m].ToString();
            }
            l++;
        }
        // Set the range value to the chunk 2d array
        ws.Range[ws.Cells[2 + processed, 1], ws.Cells[processed + chunkSize + 1, data2DLength]].value = chunkData;
        processed += chunkSize;
    }

    // Auto fit columns and rows, show excel, save.. etc
    excel.Columns.AutoFit();
    excel.Rows.AutoFit();
    excel.Visible = true;                
}

// Stop the stopwatch and display the seconds elapsed
sw.Stop();
MessageBox.Show(sw.Elapsed.TotalSeconds.ToString());

【讨论】:

  • 我知道这已经晚了,但我尝试将您的选项 2 用于我的问题(这与 OP 的问题非常相似),但我无法投射工作表。我想知道这个解决方案是否支持 .net framework 2.0,因为我的应用是旧应用?
【解决方案3】:

你可以试试这个功能:

在数据表中设置数据之后。

Public Shared Sub ExportDataSetToExcel(ByVal ds As DataTable, ByVal filename As String)
        Dim response As HttpResponse = HttpContext.Current.Response
        response.Clear()
        response.Buffer = True
        response.Charset = ""
        response.ContentType = "application/vnd.ms-excel"

        Using sw As New StringWriter()
            Using htw As New HtmlTextWriter(sw)
                Dim dg As New DataGrid()
                dg.DataSource = ds
                dg.DataBind()
                dg.RenderControl(htw)
                response.Charset = "UTF-8"
                response.ContentEncoding = System.Text.Encoding.UTF8
                response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble())
                response.Output.Write(sw.ToString())
                response.[End]()
            End Using
        End Using
    End Sub

【讨论】:

    【解决方案4】:

    我更喜欢 Microsoft Open XML SDK 的 Open XML Writer。 Open XML 是所有新办公文件的格式。

    Export a large data query (60k+ rows) to Excel

    Vincent Tan 有一篇关于该主题的精彩文章。

    http://polymathprogrammer.com/2012/08/06/how-to-properly-use-openxmlwriter-to-write-large-excel-files/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-10
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多