ADO.NET +大量INSERT + Excel + C#=“糟糕的时间”吗?

时间:2008-11-11 05:01:46

标签: c# excel ado.net memory-management memory-leaks

基本上我需要将一堆数据插入Excel文件。创建OleDB连接似乎是最快的方式,但我已经看到遇到了内存问题。当我执行INSERT查询时,进程使用的内存似乎在不断增长。我把它们缩小到仅当我输出到Excel文件时(内存保持稳定而没有输出到Excel)。我关闭并重新打开每个工作表之间的连接,但这似乎不会影响内存使用(Dispose()也是如此)。数据写成功,因为我可以用相对较小的数据集进行验证。如果有人有洞察力,我们将不胜感激。

在构造函数

中调用

initializeADOConn()

initADOConnInsertComm()创建插入参数化插入查询

每当写入新记录时,都会调用

writeRecord()。根据需要创建新工作表。

public bool initializeADOConn()
        {
            /* Set up the connection string and connect.*/
            string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0;" +
                "Data Source=" + this.destination + ";Extended Properties=\"Excel 8.0;HDR=YES;\"";
            //DbProviderFactory factory =
                //DbProviderFactories.GetFactory("System.Data.OleDb");
            conn = new OleDbConnection(connectionString);
            conn.ConnectionString = connectionString;
            conn.Open();

            /* Intialize the insert command. */
            initADOConnInsertComm();
            return true;
        }
    public override bool writeRecord(FileListerFileInfo file)
            {
                /* If all available sheets are full, make a new one. */
                if (numWritten % EXCEL_MAX_ROWS == 0)
                {
                    conn.Close();
                    conn.Open();
                    createNextSheet();
                }
                /* Count this record as written. */
                numWritten++;
                /* Get all of the properties of the FileListerFileInfo record and add
                 * them to the parameters of the insert query. */
                PropertyInfo[] properties = typeof(FileListerFileInfo).GetProperties();
                for (int i = 0; i < insertComm.Parameters.Count; i++)
                    insertComm.Parameters[i].Value = properties[i].GetValue(file, null);
                /* Add the record. */
                insertComm.ExecuteNonQuery();

                return true;
            }

编辑:

不,我根本不使用Excel。我故意避免使用Interop.Excel,因为它的性能很差(至少从我的涉猎方面来看)。

3 个答案:

答案 0 :(得分:2)

答案是,您描述的公式 等于错误的时间。

如果你有一个方便的数据库(SQL Server或Access对此很好),你可以将所有插入到数据库表中,然后将表一次性导出到Excel电子表格中。

一般来说,数据库擅长处理大量插入内容,而电子表格则不然。

答案 1 :(得分:1)

以下是一些想法:

目标工作簿是否打开?有一个错误(Memory leak occurs when you query an open Excel worksheet by using ActiveX Data Objects),其中IIRC实际上是Jet的OLE DB提供程序(您正在使用),尽管在上面的文章中未对此进行确认。

无论如何,批量插入似乎是要走的路。

您可以使用相同的Jet OLE DB提供程序来执行此操作:您只需要一行表。你甚至可以在飞行中制作一个。要创建新的Excel工作簿,请使用连接字符串中不存在的xls文件执行CREATE TABLE DDL,并且提供程序将为您创建工作簿,并使用工作表来表示该表。您已连接到Excel工作簿,因此可以执行此操作:

CREATE TABLE [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable 
(
   x FLOAT
);

(更好的IMO将是制作Jet数据库,即.mdb文件)。

使用INSERT创建虚拟行:

INSERT INTO [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable (x) 
   VALUES (0);

然后,仍然使用与目标工作簿的连接,您可以使用类似于以下内容的方法在一次命中中将值的派生表(DT1)创建为INSERT

INSERT INTO MyExcelTable (key_col, data_col)
SELECT DT1.key_col, DT1.data_col
FROM (
   SELECT 22 AS key_col, 'abc' AS data_col
   FROM [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable
   UNION ALL
   SELECT 55 AS key_col, 'xyz' AS data_col
   FROM [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable
   UNION ALL
   SELECT 99 AS key_col, 'efg' AS data_col
   FROM [EXCEL 8.0;DATABASE=C:\MyFabricatedWorkbook;HDR=YES].OneRowTable
) AS DT1;

答案 2 :(得分:0)

您是否可以找到以批量容量插入的方式,而不是一次写一条记录?我尽量不使用疯狂的DataSet东西,但是有没有办法让你的所有插入首先发生在本地,然后让它们一举上升? 此进程是否在后台打开Excel?这些过程后来会死吗?