来自DataTable的MySqlBulkLoader - VB.net

时间:2017-03-06 14:13:21

标签: mysql vb.net bulkinsert bulkloader

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

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")

1 个答案:

答案 0 :(得分:1)

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

' 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写入部分内容

临时步骤花了9秒从XML中选择部分,15秒写入CSV,7秒用于MySQL加载数据。

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

唯一的"技巧"是格式化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 只是一个显示属性的类,它是较大XML数据中的所需列。它的作用是:a)尽快删除你不需要/想要的无关列; b)提供'持有者'用于CSVHelper的数据。

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