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
| 固定リンク
この記事へのコメントは終了しました。
コメント