将一个大型数据查询(超过60k行)导出到Excel。
将一个大型数据查询(超过60k行)导出到Excel。
我在内部Web应用程序中创建了一个报告工具。报告以GridView的形式显示所有结果,并使用JavaScript逐行读取GridView的内容到Excel对象中。JavaScript继续在不同的工作表上创建一个数据透视表。
不幸的是,我没有预料到GridView的大小会导致浏览器过载问题,如果返回的天数超过几天。应用程序每天有几千条记录,假设每月有60k条记录,理想情况下,我希望能够返回一年内的所有结果。行数导致浏览器挂起或崩溃。
我们使用ASP.NET 3.5在Visual Studio 2010上使用SQL Server,并且预期的浏览器是IE8。报告包括一个GridView,根据用户选择的人口从一系列存储过程中获取数据。GridView位于UpdatePanel中:
我当时对我的团队比较陌生,所以我按照他们的惯例将存储过程返回到一个DataTable中,并在代码后台中使用它作为DataSource:
(我知道你在想什么!但是是的,我之后学到了更多关于参数化的知识。)
LINQToDataTable函数并没有什么特别之处,只是将列表转换为DataTable。
对于几千条记录(最多几天),这个工作得很好。GridView显示结果,用户可以点击一个按钮来启动JScript导出器。外部JavaScript函数将每一行读入Excel工作表,然后使用它创建一个数据透视表。数据透视表很重要!
我要做的是创建一个可以处理这些数据并将其处理成Excel的解决方案(可能是客户端)。有人可能会建议使用HtmlTextWriter,但据我所知,它不允许自动生成数据透视表,并创建一个烦人的弹出警告...
我尝试过的方法有:
- 填充JSON对象 - 我仍然认为这有潜力,但我还没有找到使其工作的方法。
- 使用SQLDataSource - 我似乎无法从中获取任何数据。
- 分页并遍历页面 - 进展不一,通常很难看,而且我仍然有一个问题,即每个显示的页面都会查询和返回整个数据集。
我仍然非常乐意接受其他解决方案,但我一直在追求JSON理论。我有一个可以从DataTable生成JSON对象的工作服务器端方法。我无法弄清楚如何将该JSON传递到(外部)exportToExcel JavaScript函数...
有人可以展示一个如何将此JSON对象传递到外部JS函数的示例吗?或者任何其他导出到Excel的解决方案。
问题的原因:需要将一个包含60,000+行的大型数据查询导出到Excel中。
解决方法:可以通过使用Microsoft Open XML SDK的Open XML Writer来以相对高效的方式处理这个问题。
具体步骤如下:
1. 安装Microsoft Open SDK(如果尚未安装,可在Google上搜索“download microsoft open xml sdk”进行下载)。
2. 创建一个控制台应用程序。
3. 添加对DocumentFormat.OpenXml的引用。
4. 添加对WindowsBase的引用。
5. 尝试运行下面的测试代码(需要一些using语句)。
using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using (var workbook = SpreadsheetDocument.Create("SomeLargeFile.xlsx", SpreadsheetDocumentType.Workbook)) { ListattributeList; OpenXmlWriter writer; workbook.AddWorkbookPart(); WorksheetPart workSheetPart = workbook.WorkbookPart.AddNewPart (); writer = OpenXmlWriter.Create(workSheetPart); writer.WriteStartElement(new Worksheet()); writer.WriteStartElement(new SheetData()); for (int i = 1; i <= 50000; ++i) { attributeList = new List (); // this is the row index attributeList.Add(new OpenXmlAttribute("r", null, i.ToString())); writer.WriteStartElement(new Row(), attributeList); for (int j = 1; j <= 100; ++j) { attributeList = new List (); // this is the data type ("t"), with CellValues.String ("str") attributeList.Add(new OpenXmlAttribute("t", null, "str")); // it's suggested you also have the cell reference, but // you'll have to calculate the correct cell reference yourself. // Here's an example: //attributeList.Add(new OpenXmlAttribute("r", null, "A1")); writer.WriteStartElement(new Cell(), attributeList); writer.WriteElement(new CellValue(string.Format("R{0}C{1}", i, j))); // this is for Cell writer.WriteEndElement(); } // this is for Row writer.WriteEndElement(); } // this is for SheetData writer.WriteEndElement(); // this is for Worksheet writer.WriteEndElement(); writer.Close(); writer = OpenXmlWriter.Create(workbook.WorkbookPart); writer.WriteStartElement(new Workbook()); writer.WriteStartElement(new Sheets()); // you can use object initialisers like this only when the properties // are actual properties. SDK classes sometimes have property-like properties // but are actually classes. For example, the Cell class has the CellValue // "property" but is actually a child class internally. // If the properties correspond to actual XML attributes, then you're fine. writer.WriteElement(new Sheet() { Name = "Sheet1", SheetId = 1, Id = workbook.WorkbookPart.GetIdOfPart(workSheetPart) }); writer.WriteEndElement(); // Write end for WorkSheet Element writer.WriteEndElement(); // Write end for WorkBook Element writer.Close(); workbook.Close(); }
需要注意的是,Excel中的行编号从1开始,而不是从0开始。如果以0为索引开始编号行,将会导致“Corrupt file”错误。
另外,如果处理的数据集非常大,不要使用ToList()方法,而是使用数据读取器(data reader)的方式流式处理数据。例如,可以使用IQueryable并在foreach循环中使用它。不要一次性将所有数据都加载到内存中,否则可能会遇到内存不足或内存使用率过高的限制。
对于需要流式传输的大型文件,可以尝试直接提供输出流(output stream),而不是文件名。然而,根据这个回答(OpenXml and HttpResponse.OutputStream),OpenXML库需要能够返回到开头,因此在主机文件之前保存到文件似乎是处理大量数据的唯一选择。
这些步骤可以帮助你导出大型数据查询到Excel中。一旦理解了底层的XML架构,这个过程就会更加清晰。可以花一些时间查看有效的xlsx文件中的底层xml结构,以便更好地理解。
出现的原因:
该问题的原因是因为要导出的数据量非常大,超过了60k+行,导致在客户端处理和显示时出现了超时和浏览器问题。
解决方法:
一种解决方法是使用服务器端方法来处理导出操作。可以在页面上添加一个"Export"按钮,将其与服务器端的方法绑定,在该方法中获取数据集并将其转换为CSV格式。然后调整响应头,使浏览器将其视为下载。实现服务器端的记录分页后,可以解决超时和浏览器问题。
另一种解决方法是使用C#中的API来进行高级工作簿Excel文件的创建。可以在C#中对数据进行透视和操作,然后将其导出为CSV格式。
这些解决方法都是服务器端的解决方案,可以在保证导出大数据查询的同时,仍然能够通过编程方式操作Excel生成透视表。