超高速にcsvからデータを取得するライブラリを作ってみた
その名も getdatafromcsvbuffer。V8のHeap領域を使わずにcsvからデータを取得するという試みで作ったライブラリ。
なぜ既存のcsv parserは遅いのか
既存のcsv parserは、文字列化などの理由でV8のHeap領域を使用する。V8で扱われるオブジェクトはメタ情報やメモリ上のポインタ的な情報を持つなど、多くのデータ構造の上で扱われる。
csvを読み込んで配列やオブジェクトとして扱うためにはV8 Heap上にデータを持つ必要があるが、それは大変な労力で、時間もメモリも消費する。
アプローチ:Buffer領域を直接操作する
Node.jsはC++で構築された実行環境であり、Buffer領域はV8メモリ空間の外に存在するC++の空間である。Node.jsからはC++によって提供されているインターフェース(buffer.indexOf など)を利用してBuffer領域を操作できる。
そもそも、FileStreamでcsvを読み込んだ時点では生のバイト列がBufferに格納される。これを直接操作して、csvから欲しいデータだけを取得できる関数が getDataPointRowHeaderName である。
使い方
getDataPointRowHeaderName(buffer, row, headerName)
- 第一引数:バイト列(Buffer)
- 第二引数:取得したい行番号(ヘッダーが0行目、データ本体の1行目が
row=1) - 第三引数:取得したいカラム名(ヘッダー名)
どれくらい速いのか
以下のcsvを読み込み、5行目の country を取得するケースで既存ライブラリ csv-parse と比較した。
name, age, gender, country, city, company
Lily, 24, femal, USA, NewYork, MS
Daniel, 27, male, Dutch, AS, META
John, 29, male, USA, NewYork, MS
POLE, 56, male, Brazil, Sanpauro, META
emily, 45, femal, France, Pari, AWS
環境:Windows11 / Node.js v26.5.0
| getDataPointRowHeaderName | csv-parse | |
|---|---|---|
| 1回目 | 2.625ms | 4.399ms |
| 2回目 | 2.81ms | 4.368ms |
| 3回目 | 2.509ms | 4.288ms |
小さいcsvの1回の処理で1.5倍以上の速度を出してくれる。大きなワークロードで大きなcsvだとより効果を発揮しそうである。
npmとGitHubで公開中
興味がある方、ぜひご確認ください!些細なことでもコメント(issueなど)くれたら嬉しいです!