📑

「データ指向アプリケーションデザイン 第3章」の感想

2025/01/01に公開

第3章を読み進める中で、「列指向ストレージがどのようにデータを扱い、なぜ書き込みに弱いのか」という点が非常に印象深く感じられました。ここでは、自分がSlackにメモした内容を振り返りながら、気づいたポイントを簡潔にまとめてみます。

1. 列指向の仕組みを知ると「* SELECT」が重い理由がわかった

BigQueryで SELECT * を行うとメモリ使用量が急増し、コストが跳ね上がるケースがあるのは、列指向ストレージの性質と深く関係しているとわかりました。特定の列だけを読めば必要最小限のI/Oで済む一方、すべての列を対象にすると大きなデータ量を読み込むことになり、列指向の恩恵を受けづらくなるという仕組みです。

2. 圧縮技術(ビットマップやランレングス)の強み

ビットマップやランレングスエンコーディングなどの軽量な圧縮技術を組み合わせると、大規模データでも驚くほど小さく格納できると再認識しました。ユニークな値の数(カーディナリ)が低いほど圧縮効率が上がり、BigQueryの高速集計もこの原理で実現されていることを改めて理解できました。

3. Verticaのようにソート順を複数持つアイデア

Verticaなどのシステムではデータを複数のソート順序で保持して、クエリに応じて最適なバージョンを使う手法を取っている点が興味深かったです。どうせレプリケーションが必要なら、異なる並び替え方の“クローン”を用意し、よく使われるクエリの条件に合わせて読み取りを最適化するという発想は、非常に効率的だと感じました。

4. 列指向ストレージの書き込みの難しさ

大規模な読み取り処理(集計や分析クエリ)には抜群の性能を発揮する一方、列指向ストレージは行単位の更新が苦手です。ソートされているテーブルに行を挿入すると、全ての列ファイルを書き直す必要があるという話は、非常に腹落ちしました。

5. LSMツリーやWOS/ROS方式での解決策

VerticaのWOS(Write Optimized Store)とROS(Read Optimized Store)のように、

  • WOS: 行指向で書き込みを受け付けるメモリ上の領域
  • ROS: ソート+圧縮済みの列指向ストア
    という二段構えにすることで、書き込み性能と読み込み性能の両立を図る手法は勉強になりました。書き込みはまずWOSへサッと入れ、一定量たまったらバックグラウンドでROSへマージするイメージが自分の中でも整理できました。

6. バッチ取り込みとマージ処理

細かい行ごとに挿入するのではなく、一定の単位でまとめて書き込むバッチ取り込み(マイクロバッチ)方式が、列指向ストアでは推奨されるという点も納得です。更新処理は「削除フラグ」などで一時的に対応し、後からマージやコンパクションのタイミングで実データを圧縮し直すという流れは、LSMツリーに近い発想だと感じました。

7. OLTPとOLAPの違いを意識するとクエリが変わる

トランザクション処理(OLTP)と分析処理(OLAP)では、データの保持の仕方が大きく異なると改めて痛感しました。

  • OLTP: 行単位の更新・ロック・整合性が重要
  • OLAP: 一度に大量のデータを読み取って集計するのが主目的
    BigQueryのような分析向けDBに対し、どういうクエリを投げれば恩恵を得やすいのか、逆にどんなクエリは苦手なのかを考えるきっかけとなりました。

まとめ

「列指向ストレージは読み込み最適化のための仕組み」という理解が深まり、BigQueryに対しても「なるべく必要な列だけ選択する」「書き込み方法を工夫する」という視点が増えました。特に圧縮やソート、LSMツリー的な考え方を知ることで、今後はクエリ設計やデータロード設計をより最適化できそうです。第3章は、実際の現場でビッグデータを扱う際に欠かせない「OLAPとOLTPの違い」と「列指向ストレージの本質」を再確認できる内容でした。

Discussion