go-sql-driver/mysql のバッファサイズが4KiBなのは小さすぎる??

qiita.com

go-sql-driver/mysql のバッファサイズは4KiBで、大きいクエリを送るなり大きいパケットを受信すれば自動的に増えますが、小さいrowを大量に受信する場合は4KiBのバッファを使って何度もReadをしてしまいます。これを大きくすればReadの回数が減って高速化できそうな気がします。

ということで、話題のリポジトリをforkして、DBからselectしてCSVを書き出す部分だけを100回ループしてみました。CSVの書き出しがネックにならないようにbufio.NewWriterSize()を使ってバッファリングしてあります。

profiling · methane/bench-docker@c333bd0 · GitHub

テスト環境は手元の MacBook Pro 13 (Retina, 13-inch, Mid 2014) で、あまり厳密なベンチではありません。

まずはバッファサイズ4KiBの場合のプロファイル結果。

f:id:methane:20201217170259p:plain
flamegraph (バッファサイズ 4KiB)

rows.Next が 3.01s で、呼び出し元の work は 3.33s です。

次にバッファサイズ16KiBの場合のプロファイル結果。

f:id:methane:20201217170529p:plain
flamegraph (バッファサイズ 16KiB)

rows.Next が 2.83s に減りましたが、期待したほどは減ってません。そして呼び出し元の work は 3.36s で、微妙に増えてしまいました。CSVを書き出すための fmt.Fprintf や Time.Format() が若干遅くなってしまってrows.Next の高速化分を打ち消してしまっています。

システムコールのオーバーヘッドの大きさにも依存しますが、むやみにバッファサイズを大きくしてもキャッシュに与える悪影響でシステムコールの回数を減らす効果が打ち消されるのかもしれません。

@kazuho さんさすがです。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。