« MySQL Insertが遅い! ので実験してみた | トップページ | VB ArrayList,LIST(Of T),配列 比較 »

2015年3月10日 (火)

VB 文字列連結 高速化

私の前回の記事「MySQL Insertが遅い! ので実験してみた」でマルチプルインサートを使用することでInsert文が高速になるが,代わりにSQL作成時間が長くなるため両者のトレードオフになると結論付けました。

その後,例によって私が知らないだけでVisualBasicでの文字列連結も高速化出来るのでは? と思いネット検索したところ,すぐに見つかりました。
文字列処理を高速に行う: .NET Tips: C#, VB.NET
いつもお世話になっているサイトです。結論として「StringBuilderクラス」を使うと見違えるほど早くなるとのこと。特にループで文字列を連結させる場合は効果が大きい,と。

そこで早速,前回のSQL文作成用プログラムコードを流用して実験してみました。

結果
※10万行のSQL文を文字列連結回数で割った回数分作成した合計時間。

文字列連結回数 String[秒] StringBuilder[秒]
1 0.998 1.149
5 0.526 0.458
10 0.568 0.311
50 1.525 0.244
100 2.679 0.263
500 10.425 0.237
1000 25.605 0.281
10000 271.244 0.221

もはや比較するレベルでは無いですね。StringBuilderの方が圧倒的に早く,10回ループあたりから差がつきだし,ループ回数が増えるほど高速になります。
SQLのInsert実行は「StringBuilderクラス」+「マルチプルインサート」が最強であることが分かりました。この結果から目一杯SQL文を連結して一気に処理するのが一番早いことになります。

但し,注意点があります。MySQLサーバーにデータを送る際のサイズには制限があります。
MySQLの設定ファイル「my.ini」に「max_allowed_packet=4M」と記載されておりデフォルトでは最大4MByteです。最大で16MBまで設定出来るようですが,常にこの設定サイズを意識しながら可能な文字列連結回数を見積もる必要があります。


うーむ,それにしても自分の無知が怖い…


検証に使用したVisualBasicのソースコード
-----------------------------------------------------------
Imports System.Text

Public Class Form1

Private Sub Button1_Click(sender As Object, _
e As EventArgs) Handles Button1.Click

Dim swMake As New System.Diagnostics.Stopwatch()
Dim sqlStr As String = Nothing
Dim repeat1 As Integer
Dim repeat2 As Integer
Dim strClass As String = Nothing
Dim mes As String
Dim loop1 As Integer
Dim loop2 As Integer
Dim loop3 As Integer

For loop1 = 1 To 9
If loop1 = 1 Then repeat1 = 1
If loop1 = 2 Then repeat1 = 5
If loop1 = 3 Then repeat1 = 10
If loop1 = 4 Then repeat1 = 50
If loop1 = 5 Then repeat1 = 100
If loop1 = 6 Then repeat1 = 500
If loop1 = 7 Then repeat1 = 1000
If loop1 = 8 Then repeat1 = 5000
If loop1 = 9 Then repeat1 = 10000
repeat2 = 100000 / repeat1
For loop2 = 1 To 2
If loop2 = 1 Then strClass = "String "
If loop2 = 2 Then strClass = "StringBuilder "
For loop3 = 1 To repeat2
swMake.Start()
If loop2 = 1 Then sqlStr = makeSqlStr1(repeat1)
If loop2 = 2 Then sqlStr = makeSqlStr2(repeat1)
swMake.Stop()
Next loop3
mes = strClass & "文字列作成 " & repeat1 & "×" & repeat2 & " "
Console.WriteLine(mes & swMake.Elapsed.ToString)
swMake.Reset()
Next loop2
Next loop1

Application.Exit()

End Sub

'Stringクラスでの文字列結合
Private Function makeSqlStr1(repeat As Integer) As String

Dim workStr As String
Dim dtToday As DateTime = DateTime.Today
Dim loop1 As Integer

workStr = "INSERT INTO test1 "
workStr &= "(date,dataA,dataB,dataC,dataD) "
workStr &= "VALUES "
For loop1 = 1 To repeat
workStr &= "('" & dtToday.ToString & "',"
workStr &= "'テストテストテスト',"
workStr &= loop1.ToString & ","
workStr &= "1234567890,"
workStr &= "1234567.89"
workStr &= "),"
Next
workStr = workStr.TrimEnd(","c)
workStr &= ";"

Return workStr

End Function

'StringBuilderクラスでの文字列結合
Private Function makeSqlStr2(repeat As Integer) As String

Dim workStr As String
Dim dtToday As DateTime = DateTime.Today
Dim sb1 As New StringBuilder()
Dim loop1 As Integer

'StringBuilderのバッファーサイズを決めるために
'ダミーで文字列を作成
sb1.Append("('")
sb1.Append(dtToday.ToString)
sb1.Append("',")
sb1.Append("'テストテストテスト',")
sb1.Append(loop1.ToString)
sb1.Append(",")
sb1.Append("1234567890,")
sb1.Append("1234567.89")
sb1.Append("),")

'バッファーサイズを指定,余裕を見て3倍にしてある
Dim sb2 As New StringBuilder(sb1.Length * repeat * 3)

sb2.Append("INSERT INTO test1 ")
sb2.Append("(date,dataA,dataB,dataC,dataD) ")
sb2.Append("VALUES ")
For loop1 = 1 To repeat
sb2.Append("('")
sb2.Append(dtToday.ToString)
sb2.Append("',")
sb2.Append("'テストテストテスト',")
sb2.Append(loop1.ToString)
sb2.Append(",")
sb2.Append("1234567890,")
sb2.Append("1234567.89")
sb2.Append("),")
Next
workStr = sb2.ToString
workStr = workStr.TrimEnd(","c)
workStr &= ";"

Return workStr

End Function

End Class

|

« MySQL Insertが遅い! ので実験してみた | トップページ | VB ArrayList,LIST(Of T),配列 比較 »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/206107/61258442

この記事へのトラックバック一覧です: VB 文字列連結 高速化:

« MySQL Insertが遅い! ので実験してみた | トップページ | VB ArrayList,LIST(Of T),配列 比較 »