[英]Fast Export of Large Datatable to Excel Spreadsheet in VB.Net
我在這里有一個有趣的難題,我如何快速(在1分鍾內)將大型數據表(從SQL填充,35,000行)導出到用戶的Excel電子表格中。 我有代碼可以處理導出,雖然代碼本身並沒有“錯誤”,但導出整個文件需要4分鍾才會非常慢(如果用戶RAM較少或者運行更多,有時會更長)他們的系統)。 可悲的是,這是使用舊方法過去10多分鍾的改進。 簡而言之,如果不使用第三方組件,可以更快地制作嗎? 如果是這樣,怎么樣? 我的代碼如下,在寫入每行的消息框6和7之間發生減速。 謝謝大家花時間看看這個:
Private Sub btnTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnJeffTest.Click
Test(MySPtoExport)
End Sub
Private Sub Test(ByVal SQL As String)
'Declare variables used to execute the VUE Export stored procedure
MsgBox("start stop watch")
Dim ConnectionString As New SqlConnection(CType(ConfigurationManager.AppSettings("ConnString"), String))
Dim cmdSP As New SqlClient.SqlCommand
Dim MyParam As New SqlClient.SqlParameter
Dim MyDataAdapter As New SqlClient.SqlDataAdapter
Dim ExportDataSet As New DataTable
Dim FilePath As String
MsgBox("stop 1 - end of declare")
Try
' open the connection
ConnectionString.Open()
' Use the connection for this sql command
cmdSP.Connection = ConnectionString
'set this command as a stored procedure command
cmdSP.CommandType = CommandType.StoredProcedure
'get the stored procedure name and plug it in
cmdSP.CommandText = SQL
'Add the Start Date parameter if required
Select Case StDt
Case Nothing
' there's no parameter to add
Case Is = 0
' there's no parameter to add
Case Else
'add the parameter name, it's direction and its value
MyParam = cmdSP.Parameters.Add("@StartDate", SqlDbType.VarChar)
MyParam.Direction = ParameterDirection.Input
MyParam.Value = Me.txtStartDate.Text
End Select
MsgBox("stop 2 - sql ready")
'Add the End Date parameter if required
Select Case EdDt
Case Nothing
' there's no parameter to add
Case Is = 0
' there's no parameter to add
Case Else
'add the parameter name, it's direction and its value
MyParam = cmdSP.Parameters.Add("@EndDate", SqlDbType.VarChar)
MyParam.Direction = ParameterDirection.Input
MyParam.Value = Me.txtEndDate.Text
End Select
'Add the single parameter 1 parameter if required
Select Case SPar1
Case Is = Nothing
' there's no parameter to add
Case Is = ""
' there's no parameter to add
Case Else
'add the parameter name, it's direction and its value
MyParam = cmdSP.Parameters.Add(SPar1, SqlDbType.VarChar)
MyParam.Direction = ParameterDirection.Input
MyParam.Value = Me.txtSingleReportCrt1.Text
End Select
'Add the single parameter 2 parameter if required
Select Case Spar2
Case Is = Nothing
' there's no parameter to add
Case Is = ""
' there's no parameter to add
Case Else
'add the parameter name, it's direction and its value
MyParam = cmdSP.Parameters.Add(Spar2, SqlDbType.VarChar)
MyParam.Direction = ParameterDirection.Input
MyParam.Value = Me.txtSingleReportCrt2.Text
End Select
MsgBox("stop 3 - params ready")
'Prepare the data adapter with the selected command
MyDataAdapter.SelectCommand = cmdSP
' Set the accept changes during fill to false for the NYPDA export
MyDataAdapter.AcceptChangesDuringFill = False
'Fill the Dataset tables (Table 0 = Exam Eligibilities, Table 1 = Candidates Demographics)
MyDataAdapter.Fill(ExportDataSet)
'Close the connection
ConnectionString.Close()
'refresh the destination path in case they changed it
SPDestination = txtPDFDestination.Text
MsgBox("stop 4 - procedure ran, datatable filled")
Select Case ExcelFile
Case True
FilePath = SPDestination & lblReportName.Text & ".xls"
Dim _excel As New Microsoft.Office.Interop.Excel.Application
Dim wBook As Microsoft.Office.Interop.Excel.Workbook
Dim wSheet As Microsoft.Office.Interop.Excel.Worksheet
wBook = _excel.Workbooks.Add()
wSheet = wBook.ActiveSheet()
Dim dt As System.Data.DataTable = ExportDataSet
Dim dc As System.Data.DataColumn
Dim dr As System.Data.DataRow
Dim colIndex As Integer = 0
Dim rowIndex As Integer = 0
MsgBox("stop 5 - excel stuff declared")
For Each dc In dt.Columns
colIndex = colIndex + 1
_excel.Cells(1, colIndex) = dc.ColumnName
Next
MsgBox("stop 6 - Header written")
For Each dr In dt.Rows
rowIndex = rowIndex + 1
colIndex = 0
For Each dc In dt.Columns
colIndex = colIndex + 1
_excel.Cells(rowIndex + 1, colIndex) = dr(dc.ColumnName)
Next
Next
MsgBox("stop 7 - rows written")
wSheet.Columns.AutoFit()
MsgBox("stop 8 - autofit complete")
Dim strFileName = SPDestination & lblReportName.Text & ".xls"
If System.IO.File.Exists(strFileName) Then
System.IO.File.Delete(strFileName)
End If
MsgBox("stop 9 - file checked")
wBook.SaveAs(strFileName)
wBook.Close()
_excel.Quit()
End Select
MsgBox("File " & lblReportName.Text & " Exported Successfully!")
'Dispose of unneeded objects
MyDataAdapter.Dispose()
ExportDataSet.Dispose()
StDt = Nothing
EdDt = Nothing
SPar1 = Nothing
Spar2 = Nothing
MyParam = Nothing
cmdSP.Dispose()
cmdSP = Nothing
MyDataAdapter = Nothing
ExportDataSet = Nothing
Catch ex As Exception
' Something went terribly wrong. Warn user.
MessageBox.Show("Error: " & ex.Message, "Stored Procedure Running Process ", _
MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
'close the connection in case is still open
If Not ConnectionString.State = ConnectionState.Closed Then
ConnectionString.Close()
ConnectionString = Nothing
End If
' reset the fields
ResetFields()
End Try
End Sub
與使用VBA自動化Excel時一樣,您可以將數組直接分配給Range對象的值:這是作為單個操作完成的,因此您可以消除與.Net代碼之間的過程邊界進行多次調用相關的開銷。 Excel實例。
例如,請參閱此處接受的答案: 將數組寫入Excel范圍
這是我自己的一段代碼,可以將數據從DataTable 快速導出到Excel工作表(使用“秒表”對象來比較速度並讓我發表評論):
Dim _excel As New Excel.Application
Dim wBook As Excel.Workbook
Dim wSheet As Excel.Worksheet
wBook = _excel.Workbooks.Add()
wSheet = wBook.ActiveSheet()
Dim dc As System.Data.DataColumn
Dim colIndex As Integer = 0
Dim rowIndex As Integer = 0
'Nombre de mesures
Dim Nbligne As Integer = DtMesures.Rows.Count
'Ecriture des entêtes de colonne et des mesures
'(Write column headers and data)
For Each dc In DtMesures.Columns
colIndex = colIndex + 1
'Entête de colonnes (column headers)
wSheet.Cells(1, colIndex) = dc.ColumnName
'Données(data)
'You can use CDbl instead of Cobj If your data is of type Double
wSheet.Cells(2, colIndex).Resize(Nbligne, ).Value = _excel.Application.transpose(DtMesures.Rows.OfType(Of DataRow)().[Select](Function(k) CObj(k(dc.ColumnName))).ToArray())
Next
我們有一個VB.NET應用程序正是這樣做的,並且對於那些使用慢速PC的用戶來說花費的時間更長......有時候是15分鍾。
該應用程序現在是一個ASP / VB.NET應用程序,它只是構建一個HTML表格並將結果輸出為.xls擴展名... excel能夠讀取HTML表格並將其解析為網格格式。 您仍然可以傳入XML格式和選項,水平窗格鎖定等。
如果您沒有使用ASP.NET的選項...嘗試尋找一種構建HTML表字符串的方法,並為您進行excel解析和填充...更快! 我確信excel也可以解析其他類型...... XML,數組,HTML等...所有這些都比通過VB.NET對象手動構建每一行更快。
即使幾年前問過這個問題,我想我會添加我的解決方案,因為問題是在VB中提出的,而“最佳答案”是在C#中。 該解決方案在具有16GB RAM的i7系統上在4秒內寫入22,000多行(1.9MB)。
Imports Excel = Microsoft.Office.Interop.Excel
Public Class Main
Private Sub btnExportToExcel(sender As Object, e As EventArgs) Handles btnExpToExcel.Click
'Needed for the Excel Workbook/WorkSheet(s)
Dim app As New Excel.Application
Dim wb As Excel.Workbook = app.Workbooks.Add()
Dim ws As Excel.Worksheet
Dim strFN as String = "MyFileName.xlsx" 'must have ".xlsx" extension
'Standard code for filling a DataTable from SQL Server
Dim strSQL As String = "My SQL Statement for the DataTable"
Dim conn As New SqlConnection With {.ConnectionString = "My Connection"}
Dim MyTable As New DataTable
Dim cmd As New SqlCommand(strSQL, conn)
Dim da As New SqlDataAdapter(cmd)
da.Fill(MyTable)
'Add a sheet to the workbook and fill it with data from MyTable
'You could create multiple tables and add additional sheets in a loop
ws = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count))
DataTableToExcel(MyTable, ws, strSym)
wb.SaveAs(strFN) 'save and close the WorkBook
wb.Close()
MsgBox("Export complete.")
End Sub
Private Sub DataTableToExcel(dt As DataTable, ws As Excel.Worksheet, TabName As String)
Dim arr(dt.Rows.Count, dt.Columns.Count) As Object
Dim r As Int32, c As Int32
'copy the datatable to an array
For r = 0 To dt.Rows.Count - 1
For c = 0 To dt.Columns.Count - 1
arr(r, c) = dt.Rows(r).Item(c)
Next
Next
ws.Name = TabName 'name the worksheet
'add the column headers starting in A1
c = 0
For Each column As DataColumn In dt.Columns
ws.Cells(1, c + 1) = column.ColumnName
c += 1
Next
'add the data starting in cell A2
ws.Range(ws.Cells(2, 1), ws.Cells(dt.Rows.Count, dt.Columns.Count)).Value = arr
End Sub
End Class
希望能幫助到你。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.