3

VB.NETでアプリを作成して、Excelファイルから行を読み取り、それらをに入力しますDataTable

dtRow = dataTable.NewRow()
Dim startTime As DateTime = DateTime.Now

dtRow("name") = suppliers.CellValue("A", rowCount)
/* SNIP - just more string retrieval */
dtRow("statistics") = suppliers.CellValue("P", rowCount)

dataTable.Rows.Add(dtRow)

Dim endTime As DateTime = DateTime.Now

Debug.Print(String.Format("Time elapsed to retrieve '{0}': {1} ms", rowCount, (endTime - startTime).ToString("fffffff")))

CellValueこれは私自身の作成ですが、これは小さな関数であり、すでに経過時間を測定しています。かなり速いです。

ただし、10,000行のExcelファイル(同じデータで埋められている)を開くと、処理にかかる時間が大幅に遅くなります。

3,000行

Time elapsed to retrieve '2': 0510051 ms
Time elapsed to retrieve '3': 0500050 ms
Time elapsed to retrieve '4': 0340034 ms
Time elapsed to retrieve '5': 0350035 ms
Time elapsed to retrieve '6': 0340034 ms
Time elapsed to retrieve '7': 0340034 ms
Time elapsed to retrieve '8': 0350035 ms

6,000行

Time elapsed to retrieve '2': 0710071 ms
Time elapsed to retrieve '3': 0760076 ms
Time elapsed to retrieve '4': 0620062 ms
Time elapsed to retrieve '5': 0670067 ms
Time elapsed to retrieve '6': 0750075 ms
Time elapsed to retrieve '7': 0750075 ms
Time elapsed to retrieve '8': 0700070 ms

10,000行

Time elapsed to retrieve '2': 0920092 ms
Time elapsed to retrieve '3': 0920092 ms
Time elapsed to retrieve '4': 1790179 ms
Time elapsed to retrieve '5': 1810181 ms
Time elapsed to retrieve '6': 1930193 ms
Time elapsed to retrieve '7': 2240224 ms
Time elapsed to retrieve '8': 1820182 ms

ここに画像の説明を入力してください

なぜこれが発生するのですか?修正できますか?

編集:suppliersこのコンストラクターを使用して、Excelファイルを処理するために作成したクラスです:

Public Sub New(ByVal doc As SpreadsheetDocument, ByVal sheetName As String)
    pWorkbookPart = doc.WorkbookPart

    Dim sheet As Sheet = pWorkbookPart.Workbook.Descendants(Of Sheet).Where(Function(s) s.Name = sheetName).FirstOrDefault()

    pWorksheetPart = CType(pWorkbookPart.GetPartById(sheet.Id), WorksheetPart)

    pSharedStringTable = pWorkbookPart.GetPartsOfType(Of SharedStringTablePart).FirstOrDefault()
End Sub

CellValue

Public Function CellValue(ByVal column As String, ByVal row As Integer) As String
    Dim cellAddress As String = column & row
    Dim cell As Cell = pWorksheetPart.Worksheet.Descendants(Of Cell).Where(Function(c) c.CellReference = cellAddress).FirstOrDefault()

    Dim index As Integer
    Dim returnValue As String

    If cell IsNot Nothing Then
        If cell.DataType IsNot Nothing Then
            index = Integer.Parse(cell.InnerText)
            returnValue = pSharedStringTable.SharedStringTable.ElementAt(index).InnerText
        Else
            returnValue = CStr(cell.InnerText)
        End If
    End If

    Return returnValue
End Function
4

2 に答える 2

6

文字列テーブルが非常に大きくなっElementAtた場合に考えられる問題の 1 つは、SharedStringTable. このテーブルは処理に関して静的であるため、その部分を取り除き、代わりにList<string>または配列を使用して保存することをお勧めします。

' Use this instead of pSharedStringTable
' Dim sharedStringTable As New List(Of String)

' Initialize your string table
sharedStringTable.AddRange( _
    From xml In pSharedStringTable.SharedStringTable _
    Select xml.InnerText)

' Now you can use sharedStringTable.ElementAt(index) and enjoy optimization
' Or you can use sharedStringTable(index)

別の考えられる問題は、参照によるセルの一定の線形検索です。代わりに、これを辞書に変換する必要があります。

' Dim cells As New Dictionary(Of String, Of Cell)
For Each cell In pWorksheetPart.Worksheet.Descendants(Of Cell)
    cells.Add(cell.CellReference.InnerText, cell)
Next cell
' Only one round-trip to Excel for cells using this method

これらの各ケースでは、メモリを時間と交換することになります。どちらの場合も、これが最善の利益になると思います。

' Revised lookup using data structures optimized for common access
If cells.TryGetValue(cellAddress, cell) Then
    If cell.DataType IsNot Nothing Then
        index = Integer.Parse(cell.InnerText)
        returnValue = sharedStringTable(index)
    Else
        returnValue = CStr(cell.InnerText)
    End If
End If
于 2012-07-05T20:03:37.650 に答える
4

この行は怪しいようです:

Dim cell As Cell = pWorksheetPart.Worksheet.Descendants(Of Cell).Where(Function(c) c.CellReference = cellAddress).FirstOrDefault()

.Where() 条件がスプレッドシートのすべてのセルに対して実行される場合。行数が増えると、セル アドレス比較の数は (行 x 列) だけ増えます。セル参照の比較操作が単純な場合でも、すぐに加算されます。

表示されている OpenXML または Workbook クラスが便利な x、y セル アドレッシングを提供しない場合は、独自のインデックスを作成する必要がある場合があります。すべてのセルを 1 回パスして、それらを独自の列リストに追加すると、放棄して x、y でインデックスを付けることができます。x = 列のリストからの列リストのインデックス、y = セルをフェッチするための列リストへのインデックス。

于 2012-07-05T20:05:39.210 に答える