.netでExcelを出力する際に、
処理が遅い場合の見直しポイントを備忘録として残します。
大事なことは、Excelへのアクセス回数を最小限にすることに尽きます。
1セルずつRangeやCellにアクセスして、
値設定 ⇒ 参照の解放 としていると、
1万セル程度でも相当遅くなってしまいます。
あとはExcelのプロパティ設定ですね、
当記事では、よく言われる下記の3つのプロパティを検証します。
検証条件は↓
※遅延バインディングしているため、参照の設定は不要です。
今回、アクセス方法や、プロパティの設定による速度差がどの程度でるのか検証します。
まず、VisualStudio(c#)でテストフォームを作成します。

次に処理です。
各ボタンクリックイベントは省略。
メイン関数のみ載せます。
private void Export(bool isBulk, bool screenUpdating, bool enableEvents, int calculation, TextBox txtResult)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    dynamic xlApp = null;
    dynamic xlWbooks = null;
    dynamic xlWbook = null;
    dynamic xlSheets = null;
    dynamic xlSheet = null;
    dynamic xlRange = null;
    dynamic xlCell = null;
    try
    {
        Type objectClassType = Type.GetTypeFromProgID("Excel.Application");
        xlApp = Activator.CreateInstance(objectClassType);
        xlApp.ScreenUpdating = screenUpdating;
        xlApp.EnableEvents = enableEvents;
        xlWbooks = xlApp.Workbooks;
        xlWbook = xlWbooks.Open(@"C:\file\Book1.xlsm");
        xlApp.Calculation = calculation;
        xlSheets = xlWbook.Worksheets;
        xlSheet = xlSheets.Item("Sheet1");
        if (isBulk) //一括の場合
        {
            object[,] values = new object[100, 100]; 
            for (int iRow = 0; iRow < 100; iRow++)
            {
                for (int iCol = 0; iCol < 100; iCol++)
                {
                    values[iRow, iCol] = (iRow + 1).ToString() + (iCol + 1).ToString();
                }
            }
            try
            {
                xlRange = xlSheet.Range("A1:CV100");
                xlRange.Value = values;
            }
            finally
            {
                Marshal.ReleaseComObject(xlRange);
            }
        }
        else //1セルずつの場合
        {
            for (int iRow = 1; iRow <= 100; iRow++)
            {
                for (int iCol = 1; iCol <= 100; iCol++)
                {
                    try
                    {
                        xlCell = xlSheet.Cells(iRow, iCol);
                        xlCell.Value = (iRow).ToString() + (iCol).ToString();
                    }
                    finally
                    {
                        Marshal.ReleaseComObject(xlCell);
                    }
                }
            }
        }
        
        xlApp.Calculation = CALCULATION_DEFAULT;
        xlWbook.Save();
    }
    finally
    {
        if (xlWbook != null)
        {
            xlWbook.Saved = true;
        }
        xlApp.EnableEvents = true;
        xlApp.ScreenUpdating = true;
        //COMオブジェクトの開放
        Marshal.ReleaseComObject(xlSheet);
        Marshal.ReleaseComObject(xlSheets);
        Marshal.ReleaseComObject(xlWbook);
        Marshal.ReleaseComObject(xlWbooks);
        //Excelアプリケーション終了
        xlApp.Quit();
        Marshal.ReleaseComObject(xlApp);
        //計測結果表示
        sw.Stop();
        TimeSpan ts = sw.Elapsed;
        txtResult.Text = $"{ts.TotalSeconds:0.00}";
    }
}
実際の計測結果です。
単位は秒です。
| 項目 | 1セルずつ出力 | 一括出力 | 
|---|---|---|
| オプション無 | 27.83 | 1.04 | 
| ScreenUpdatingのみ設定 | 25.48 | 1.20 | 
| EnableEventsのみ設定 | 19.98 | 1.00 | 
| Calculationのみ設定 | 23.77 | 1.03 | 
| すべて設定 | 18.66 | 1.10 | 
まずアクセス方法の違い
1セルずつ出力か、一括出力かで圧倒的に差が出ますね。
あとはプロパティにより異なりますが
この検証条件だとScreenUpdatingよりも、EnableEventsの方が効果大ですね。
イベントの設定がない場合だと、圧倒的にScreenUpdatingの方が体感できます。
一括出力のほうのプロパティ毎の差は誤差みたいなものでしょう。
おしまい。