繁体   English   中英

CodeGo.net>如何提高foreach循环的性能

[英]c# - How to increase performance of foreach loop

我有这个C#程序,可以在其中将数据导出到Excel文件。 它在sql server中调用存储过程,并将结果返回到excel文件(基于我选择的过滤器)。

现在,我能够成功导出它,但是如果我尝试从2000万个记录表中提取更多数据(约20,000个记录),则它的时间太长了。 我在代码中添加了一个秒表,发现foreach循环是这里的罪魁祸首。

这是我的代码:

private void ExportExcel(SqlDataReader dr)
    {
        try
        {
            DataTable dt = new DataTable();
            dt.Load(dr);
            SaveFileDialog saveFileDialog1 = new SaveFileDialog();
            saveFileDialog1.Filter = "Microsoft Office Excel Workbook (*.xls)|*.xls|All Files (*.*)|*.*";
            saveFileDialog1.FilterIndex = 1;
            saveFileDialog1.RestoreDirectory = true;

            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                // Create an Excel object and add workbook...
                Excel.ApplicationClass excel = new Excel.ApplicationClass();
                Excel.Workbook workbook = excel.Application.Workbooks.Add(true); // true for object template???


               // var watch = System.Diagnostics.Stopwatch.StartNew();
                // Add column headings...
                int iCol = 0;
                int iVisibleColumnCount = 0;
                foreach (DataColumn c in dt.Columns)
                {
                    iCol++;
                    // counting visible columns
                    if (c.ColumnMapping != MappingType.Hidden)
                        iVisibleColumnCount++;
                    else    // hide the columns in excel if the column is hide in datatable
                    {
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.Hidden = true;
                        continue;
                    }
                    // Set column header text to bold
                    ((Excel.Range)excel.Cells[1, iCol]).Font.Bold = true;
                    excel.Cells[1, iCol] = c.ColumnName;

                    if (c.DataType == typeof(System.String))
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.NumberFormat = "@";
                    else if (c.DataType == typeof(System.Int16)
                        || c.DataType == typeof(System.Int32)
                        || c.DataType == typeof(System.Int64))
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.NumberFormat = "#,##0";
                    else if (c.DataType == typeof(System.TimeSpan))
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.NumberFormat = @"[$-409]hh:mm:ss AM/PM;@";
                    else if (c.DataType == typeof(System.DateTime))
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.NumberFormat = "yyyy-mm-dd hh:mm:ss";
                    else if (c.DataType == typeof(System.Decimal))
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.NumberFormat = @"#,##0.00_);[Red](#,##0.00)";
                    else
                        ((Excel.Range)excel.Cells[1, iCol]).EntireColumn.NumberFormat = "General";
                }
                // for each row of data...
                int iRow = 0;
                foreach (DataRow r in dt.Rows)
                {
                    iRow++;

                    // add each row's cell data...
                    iCol = 0;
                    foreach (DataColumn c in dt.Columns)
                    {
                        iCol++;
                        if (c.ColumnMapping != MappingType.Hidden)
                        {
                            if (c.DataType == typeof(DateTime))
                            {
                                DateTime date1 = (DateTime)r[c.ColumnName];
                                string DateTime = date1.ToString();

                                if (DateTime.Contains("AM"))
                                {
                                    excel.Cells[iRow + 1, iCol] = date1.ToString("yyyy-MM-dd hh:mm:ss") + " AM";
                                }
                                else   {
                                    excel.Cells[iRow + 1, iCol] = date1.ToString("yyyy-MM-dd hh:mm:ss") + " PM";
                                }


                            }
                            else {
                                excel.Cells[iRow + 1, iCol] = r[c.ColumnName].ToString();
                            }
                        }
                    }
                }

谁能提出一些建议,以改善导出至Excel所需的性能?

您如何通过COM互操作访问Excel?

如果是这样,您将避免避免单独设置每个单元格的值,因为这确实非常慢。 尝试将数组分配给尽可能大的范围。

例如,由于您似乎无条件地遍历了每一行,因此看起来您至少可以尝试构建代表一个列的数组/向量,并将其分配给该列中的适当范围。

没有明显的方法可以改善这一点。 如果循环花费时间(而不是sql过程),则大部分工作必须由excel库完成。 您可以针对excel寻找不同的库,如果幸运的话,您可以允许并行构建行,或者只是更快地构建行。 否则,您将只能在循环内对自己的代码进行小的优化。 您可能可以稍微改善一下日期时间代码,但是如果它会产生很大的变化,我会感到惊讶。

您需要Excel工作表还是CSV(可以由Excel打开)? 如果csv可以工作,则可以直接从sql导出,也可以自己建立并行行,而无需依赖库。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM