OLEDB读取Excel的性能表现

6

以下代码在一台i7-*3.4 GHz windows-7 64位计算机上读取一个包含25000行和5列的Excel表需要约2500毫秒。每个单元格大约包含10个字符的字符串。这正常吗?如何更快地读取?


 Stopwatch sw1 = Stopwatch.StartNew();
 var connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; " +
                                             "Extended Properties=Excel 12.0;", filename);

 var adapter = new OleDbDataAdapter("SELECT * FROM [roots$]", connectionString);
 var ds = new DataSet();
 adapter.Fill(ds, "roots");
 sw1.Stop(); Console.WriteLine("Time taken for excel roots: {0} ms", sw1.Elapsed.TotalMilliseconds);

3
数据集是“重量级”对象,最好创建自己的类并使用DataReader填充列表。 - Boomer
1
我认为大部分性能成本是连接时间(尝试修改记录集大小以查看经过的时间是否显著增加) - Pynner
尝试将StopWatch的开始移动到连接建立之后,看看这部分需要多长时间。但正如Boomer已经指出的那样,尝试使用OleDbCommand和OleDbDataReader而不是OleDbDataAdapter和DataSet,你可能也会获得相当大的速度提升。 - Karl-Johan Sjögren
1个回答

6

我希望将我的发现作为答案呈现,因为这种行为始终如一。

我复制了您的代码并放在一个按钮点击事件中,只是稍微更改了一下,以确保在进行每个测试时处理适配器和连接。

// test.xls contains 26664 rows by 5 columns. Average 10 char for column, file size is 2448kb
// OS Windows 7 Ultimate 64 bit. CPU Intel Core2 Quad Q9550 2.83ghz 
// 8gb ram and disk C is an 256gb SSD cruzer

    private void button1_Click(object sender, EventArgs e)
    {

        string filename = "c:\\tmp\\test.xls";
        Stopwatch sw1 = Stopwatch.StartNew(); 
        var connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; " + 
                                              "Extended Properties=Excel 12.0", filename);

        using(var adapter = new OleDbDataAdapter("SELECT * FROM [roots$]", connectionString))
        {
            var ds = new DataSet();
            adapter.Fill(ds, "roots");
            sw1.Stop();
            Console.WriteLine("Time taken for excel roots: {0} ms", sw1.Elapsed.TotalMilliseconds);
        }
    }

所以,这基本上是你的代码。这段代码在500ms内执行。但是... 如果我在Excel 2010中保持test.xls文件处于打开状态,执行时间会跳到8000ms。

我也尝试了这个代码变化,但最终结果都是一样的。

    private void button1_Click(object sender, EventArgs e)
    {
        string filename = "c:\\tmp\\test.xls";
        Stopwatch sw1 = Stopwatch.StartNew(); 
        var connectionString = string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source={0}; " + 
                                              "Extended Properties=Excel 12.0", filename);
        using(OleDbConnection cn = new OleDbConnection(connectionString))
        {
            cn.Open();
            using(var adapter = new OleDbDataAdapter("SELECT * FROM [roots$]", cn))
            {
                var ds = new DataSet();
                adapter.Fill(ds, "roots");
                sw1.Stop();
                Console.WriteLine("Time taken for excel roots: {0} ms", sw1.Elapsed.TotalMilliseconds);
            }
        }
    }

而且,不,它并不是OleDbConnection的Open()方法,而始终是adapter.Fill()方法。

1
我从来没想到原因是文件被打开了。谢谢你的答案。 - hrzafer
我注意到一个我曾经参与的项目也有类似的行为,它从Excel中读取大量数据。我没有进行研究以缩小原因的范围,因为该项目实际上不需要任何性能(它是一个内部工具,仍然在不到一分钟的时间内完成处理)。但我确实注意到,如果我打开了电子表格,它似乎需要一分钟才能完成,而如果电子表格没有打开,可能只需要10秒钟。我觉得这很奇怪,但这篇文章证实了我并不是疯了。 - Jim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接