DataTable 中的 MySqlBulkLoader - VB.net

MySqlBulkLoader from DataTable - VB.net

我想将大约 9.000.000 行从 xml 文件导入到 MySql 服务器。目前我正在逐行插入数据,这非常慢。我每秒可以上传大约 50 行,这意味着需要几天才能完成。对于另一个项目,我一次将类似的数据加载到一个包含 5000 行的数据 table 中,然后我将一次批量插入所有 5000 行。这使我达到了大约 7.500 行/秒。问题是 SQL 服务器,这是 MySQL。我无法从数据 table 中找到任何使用 MySqlBulkLoader class 的人。这可能吗?我该怎么做?

xml 文件中前 750 个元素的示例:http://view.qrdetector.dk/test.xml

这些是我在 xml 文件的数据库中需要的列。

    'Create datatable to hold the information from the XML file
    Dim ReadXML_DT As New DataTable
    ReadXML_DT.Columns.Add("KoeretoejIdent", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejArtNavn", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejAnvendelseNavn", GetType(String))
    ReadXML_DT.Columns.Add("RegistreringNummerNummer", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejOplysningStatus", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejOplysningFoersteRegistreringDato", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejOplysningStelNummer", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejMaerkeTypeNavn", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejModelTypeNavn", GetType(String))
    ReadXML_DT.Columns.Add("KoeretoejVariantTypeNavn", GetType(String))
    ReadXML_DT.Columns.Add("DrivkraftTypeNavn", GetType(String))
    ReadXML_DT.Columns.Add("SynResultatSynsType", GetType(String))
    ReadXML_DT.Columns.Add("SynResultatSynsDato", GetType(String))
    ReadXML_DT.Columns.Add("SynResultatSynStatusDato", GetType(String))
    ReadXML_DT.Columns.Add("SidsteSynTjek", GetType(String))

我手动制作了一个包含 130.000 行的 CSV 文件,其中包含我需要的 15 列。然后我使用了 Plutonix 回复中的批量插入代码。我现在能够在大约 215 秒内解析 130.000 行,这使我的平均速度约为 600 行/秒。这与之前的结果几乎相同。这是因为我连接到 MySQL 服务器吗?

Dim sw As Stopwatch = New Stopwatch
sw.Start()

' Finally, BulkLoad
Dim cols As String() = {"KoeretoejIdent", "KoeretoejArtNavn", "KoeretoejAnvendelseNavn", "RegistreringNummerNummer", "KoeretoejOplysningStatus", "KoeretoejOplysningFoersteRegistreringDato", "KoeretoejOplysningStelNummer", "KoeretoejMaerkeTypeNavn", "KoeretoejModelTypeNavn", "KoeretoejVariantTypeNavn", "DrivkraftTypeNavn", "SynResultatSynsType", "SynResultatSynsDato", "SynResultatSynStatusDato", "SidsteSynTjek"}
Dim rows As Integer = 0
Using dbcon As New MySqlConnection(connectionString)
    Dim bulk = New MySqlBulkLoader(dbcon)

    bulk.TableName = "synsbasen_testLoad"
    bulk.FieldTerminator = "^"
    bulk.LineTerminator = "\r\n"    ' == CR/LF
    bulk.FileName = "C:/Users/Synsbasen/Desktop/abc.csv"         ' full file path name to CSV 
    bulk.NumberOfLinesToSkip = 1    ' has a header (default)

    bulk.Columns.Clear()
    For Each s In cols
        bulk.Columns.Add(s)         ' specify col order in file
    Next

    rows = bulk.Load()
End Using
sw.Stop()
' SW is a stopwatch
MsgBox(rows & "rows converted and loaded in " & sw.Elapsed.TotalSeconds & " secs")

这将从 XML 中读取 百万行 ,提取数据子集,导出为 CSV(使用 CSVHelper),然后将它们加载到 MySql 在 大约 30 秒 中使用 MySqlBulkLoader

' Ienumberable of the data parts to import
Dim recList As IEnumerable(Of SmSample)

' load some columns as a class
Using fs As FileStream = File.OpenRead(XMLFile)
    Dim xDoc = XDocument.Load(fs)

    ' its IEnumberable - leave it that way
    recList = xDoc.Descendants("Sample").
               Select(Function(j) New SmSample With {.Name = j.Element("Name").Value,
                                 .Descr = j.Element("Descr").Value,
                                 .Price = Decimal.Parse(j.Element("Price").Value),
                                 .ItemDate = DateTime.Parse(j.Element("ItemDate").Value)
                                                    }
                      )
End Using

' Have CSVHelper write them out
' this is the most time consuming part what with Disk IO and all
Using strW As New StreamWriter(CSVFile)
    Using csv As New CsvWriter(strW)

        ' ToDo: add other things like Field sepatators etc
        csv.Configuration.RegisterClassMap(Of SmSample.CSVItemMap)()

        csv.WriteRecords(recList)
    End Using
End Using

' Finally, BulkLoad
Dim cols As String() = {"Name", "Descr", "Price", "ItemDate"}
Dim rows As Int32 = 0
Using dbcon As New MySqlConnection(MySQLConnStr)
    Dim bulk = New MySqlBulkLoader(dbcon)

    bulk.TableName = "Sample"
    bulk.FieldTerminator = ","
    bulk.LineTerminator = "\r\n"    ' == CR/LF
    bulk.FileName = CSVFile         ' full file path name to CSV 
    bulk.NumberOfLinesToSkip = 1    ' has a header (default)

    bulk.Columns.Clear()
    For Each s In cols
        bulk.Columns.Add(s)         ' specify col order in file
    Next

    rows = bulk.Load()
End Using

' SW is a stopwatch
Console.WriteLine("{0} rows converted and loaded in {1} secs", 
                          rows, sw.ElapsedMilliseconds / 1000)

你的自然会花更长的时间,但 1,000,000 行已经有点大了,所以它应该足够适当地扩展。如果您想批量加载它们,请使用 500k 之类的东西。使用 Skip()Take().

分部分编写 CSV 很容易

临时步骤 select 来自 XML 的部分花费了 9 秒,写入 CSV 花费了 15 秒,MySQL 加载数据花费了 7 秒。

你的 XML 文件的细节是个谜(link 是在发布后很好地添加到问题中的)。由于您可以将其加载到 DataTable,测试仅使用了 myDT.WriteXml(...) 的结果,因此您可能需要更改该部分。将其保留为 linq 查询并让 CSVHelper 使用它,因为小程序本身根本不需要收集数据。

唯一的 "trick" 是格式化 DateTime 字段以便 MySQL 可以解析它:

Public Class CSVItemMap
    Inherits CsvClassMap(Of SmSample)

    Public Sub New()
        AutoMap()
        Map(Function(m) m.ItemDate).TypeConverterOption("yyyy-MM-dd")
    End Sub

End Class

CSVHelper 非常酷,非常强大并且是结果不可或缺的一部分。

SmSample 只是一个 class,显示的属性是较大的 XML 数据中的所需列。它的作用是 a) 尽快摆脱你不 need/want 的无关列和 b) 提供 'holder' 数据供 CSVHelper 采取行动。

答案还使用了内置的 MySqlBulkLoader 工具,我发现它比 SQL LOAD DATA LOCAL INFILE 形式更容易使用。