検証ラボ ── 2026-09-03

17億件のティックを普通のPCで集計する — 配列に貯めるのをやめたら9秒で終わった

3年分のティックを集計しようとして、最初に書いたコードは動きませんでした。メモリが足りなくなって落ちたのです。

扱っていたのは1通貨ペアで9,300万件、最終的には22銘柄で17億件でした。専用のサーバーがあるわけでもなく、手元のPCです。

結局、貯めるのをやめることで解決しました。9,300万件の集計が9秒で終わるようになり、22銘柄でも1分かかりません。

大きなデータを扱う検証では同じ壁に当たると思うので、考え方を書き残しておきます。

何をしたかったか

やりたかったのは単純なことです。

「スプレッドの中央値と、90パーセンタイル、99パーセンタイルを、時間帯ごとに出す」

平均値なら、合計と件数を持っておけば済みます。件数がいくら増えても、メモリは増えません。

**分位点はそうはいきません。**中央値を出すには、普通は全部の値を並べて真ん中を取ります。そのためには全部を持っておく必要がある——最初はそう考えていました。

最初の失敗

素直に書くと、こうなります。

値をぜんぶ配列に入れる
 → 並べ替える
 → 真ん中を取る

9,300万件の数値を配列に入れると、それだけで数百MBから1GBを超えます。時間帯ごとに分けるなら24個、さらに曜日別にも欲しいとなると、同じデータを何セットも持つことになります。

そして並べ替えにも時間がかかります。動いたとしても、試行錯誤ができる速度ではありません。

検証では「集計してみて、切り口を変えてもう一度」を何度も繰り返します。**1回に何分もかかると、その繰り返しができなくなります。**これが一番の問題でした。

解決:値そのものを捨てて、個数だけ数える

考え方を変えました。

**スプレッドは、細かく刻んでも有限種類しかありません。**米ドル/円なら0.1銭刻みで、実測では402種類しかありませんでした。

だったら、値を保存する必要はありません。「0.5銭が何回出たか」「0.6銭が何回出たか」を数えるだけで十分です。

0.1銭 → 12,345回
0.2銭 → 234,567回
0.3銭 → 9,051,383回
0.4銭 → 10,845,605回
0.5銭 → 14,821,739回
0.6銭 → 16,748,246回   ← ここが中央値
...

この表があれば、分位点は上から足していくだけで出せます。件数の合計の半分を超えたところが中央値、90%を超えたところが90パーセンタイルです。

**しかも近似ではなく、正確な値が出ます。**元の値をすべて並べたのと同じ結果になります。

メモリがどうなるか

決定的な違いはここです。

方式メモリ
値を配列に貯める件数に比例して増える
個数を数える件数によらず一定

数える方式なら、1万件でも17億件でも使うメモリは同じです。取りうる値の種類だけで決まるからです。

これで、時間帯24通り×季節2通りに分けても平気になりました。制約が「データ量」から「値の種類」に変わったわけです。

結果

9,317万件(1通貨ペア3年分)の集計約9秒
22銘柄・17億件1銘柄あたり数十秒
メモリ件数によらず一定

速くなったことより、切り口を変えて何度でも試せるようになったことのほうが大きかったです。

実際この速度があったから、「夏時間と冬時間で分けたらどうなるか」を思いついてすぐ試せました。そして結論がひっくり返りました。遅かったら試さなかったと思います。

この考え方が使える場面・使えない場面

使える

  • 取りうる値が有限で、そこそこ少ない場合。スプレッド、pips単位の値幅、約定までの秒数など
  • 必要なのが分布の要約である場合。中央値、分位点、最大値、ヒストグラムそのもの
  • 同じデータを何通りにも切り分けたい場合。時間帯別・曜日別・銘柄別を同時に持てます

使えない

  • 値が連続で、種類が事実上無限の場合。刻んで丸めることになるので、丸めた分の精度は失われます
  • 個々のデータを後から参照したい場合。「最大値が出たのはいつか」を知りたいなら、別途その情報を持つ必要があります
  • 順序に意味がある処理。連続する値の関係を見る計算には向きません

私の場合、「最大スプレッドが出た日時」を後から知りたくなって、別のパスをもう一度書きました。捨てた情報は戻らないので、そこは割り切りです。

実務でどう使うか

  • 「全部持っておく」以外の選択肢があることを知っておくだけで、扱えるデータ量が変わります
  • 検証で大事なのは速さそのものより、試行錯誤の回数です。1回30分かかる集計は、実質1日に数回しか試せません
  • **精度を捨てているかどうかを意識してください。**刻み幅より細かい違いは見えなくなります。私の場合、スプレッドはもともと刻みがあるので損失ゼロでした
  • 大きなデータを扱う前に、**「何を出したいのか」を先に決めてください。**平均だけなら合計と件数で足ります。分位点が要るならこの方式が要ります。全件が要るなら、別の設計が要ります

限界

  • 17億件という規模での話です。もっと大きくなれば別の設計が要ります
  • **専用のデータベースやライブラリを使えば、もっと楽な方法もあります。**ここに書いたのは、追加の道具を入れずに手元で済ませる方法です
  • 実装の詳細(言語・データ構造)は環境によります。考え方の部分だけを取り出して書きました
  • 速度の数値は手元のPCでの実測です。環境によって変わります

まとめ

  • 分位点を出すのに、値を全部持っておく必要はない
  • 値ごとの個数を数えるだけで、中央値も分位点も正確に出せる
  • メモリは件数によらず一定になる。制約が「データ量」から「値の種類」に変わる
  • 9,317万件の集計が9秒。22銘柄でも1分以内
  • 速くなったこと以上に、切り口を変えて何度も試せるようになったことが効いた

検証は一度で終わりません。何度も切り直せる速度があるかどうかが、結果の質を決めていたように思います。

出典

※本記事は情報提供を目的としたもので、特定の手法や環境を推奨するものではありません。