この記事の途中に、以下の記事の引用を含んでいます。
What is index overhead on writes?
実際、インデックスの「書き込みコスト」はどれほど影響するのか?
データベース設計時によく話題になるのが「インデックスは読み取りを速くするが、書き込みを遅くする」という通説です。
多くのエンジニアが「インデックスを増やす=必ず書き込み性能が大幅に低下する」と信じて疑いません。
しかし、 それは本当にどれほど重大な影響があるのでしょうか?
今回紹介する記事「What is index overhead on writes?」では、PostgreSQL 18を使った実測データとともに「インデックス追加が書き込みパフォーマンスに与える実際の影響」について詳細に検証しています。
この実験を踏まえると、従来の常識を疑うべきポイントや、DB設計の新たな視点が見えてきます。
まさかの結果!? インデックスを増やした実験データの紹介
早速、記事から書き込み処理速度とインデックス数の関係に関する重要なデータを抜粋します。
“Table itself, without indexes, takes ~191MB. Each index is slightly different, but their sizes are all in the range of 21 to 25MB. So, total size, in easiest case with no indexes, was 191MB, and with all indexes 689MB.”
つまり、「インデックスを全く付けないときのテーブルサイズは191MB、20個のインデックスを付けると689MBまで膨らむ」という観察値です。
そして肝心の書き込み性能も詳細に記載されています:
“with ~3.6x increase in size, we see 8 times slower performance”
つまり、「データサイズは3.6倍に増えたが、書き込みパフォーマンス(INSERT時の所要時間)は8倍遅くなった」ということですね。
また、全文を読むと他にも注目すべき実験がいくつか行われています:
– 単一の幅広い(multi-column)インデックスを設定した場合
– パーシャル(部分的)インデックスを設定した場合
– GINインデックスの極端な遅延事例
このような細かな測定により、「どのようなインデックス設計が実運用上許容できるのか?」がかなり具体的に浮かび上がってきます。
インデックス追加の現実的なコストを紐解く ― 背景・解説
ここで重要なのは、「インデックス数と書き込み遅延」は必ずしも”線形”ではない、という実証データです。
前述の通り
“speed definitely decreases … the decrease is not linear with total size of table + indexes. it’s worse.”
これは無視できないポイントです。
つまりインデックスを単純に一つ追加⇒1/nだけ遅くなる、ということではなく、特定の総量を超えると急激に劣化する “閾値” のようなものが実際に存在するとも解釈できます。
ただし、その一方で、部分インデックスや複合インデックス(multi-column index)のような工夫が「コストを劇的に抑えて」くれることも事実です。
例えば
“Now, let’s see what will happen if I’ll make the indexes partial… Each of c* indexes is now only ~ 1.1MB … time to load data: 6,916.112 ms”
通常のインデックスで6万ミリ秒以上かかった処理が、パーシャルインデックスで約7千ミリ秒と大幅短縮されたことが分かります。
これは、特定のクエリだけを高速化するために「全件分ではなく、よく検索される条件だけにインデックスを貼る」という戦略が非常に有効であることを示しています。
もう一つの記事の実例では、複数カラムの複合インデックスを1本付けた場合は「同等の列ごとの単体インデックス複数本より書き込みが高速だった」との記述もあり、同じインデックスでも設計次第でパフォーマンスが大きく異なることが分かります。
データベース設計の現場に学ぶべき“重要な視点”
データベース管理や運用の実際の現場では、「読み取り」と「書き込み」の比重は必ずしも理論通りには分けられません。
例えば、
– 100件の検索(SELECT)に対して1件の書き込み(INSERT/UPDATE/DELETE)しか発生しないルックアップ用マスターテーブル
– 逆に、書き込みが大量発生するデータログ用テーブル
この2者では、インデックス最適化の戦略は根本から変わってくるはずです。
記事では次のように述べられています:
“we can add indexes without overly worrying about performance, as long as:
– index significantly improves some common operation
– your db has (much) more common this operation that it being optimized, than writes to the table that gets new index
– partial indexes are your friends – they are smaller, and faster”
これは「本当に必要な検索条件だけにピンポイントでインデックスを張る」「書き込み負荷と参照頻度のバランスを冷静に見極める」「部分インデックスや複合インデックスを活用する」というDBチューニングの鉄則と完全に合致します。
また、記事終盤では、B-treeインデックス以外の「高コスト型インデックス」(例えばGINインデックス)を不用意に増やすと、悠長では済まされないほど極端な性能劣化リスクがある事例も紹介しています:
“Now, without index, it took 6,928.514 ms to load the data. With index, though, the time jumped to 109,804.609 ms. So, total data size increased by only ~ 25%, but time increased by over 15 times.”
このケースでは、データサイズの増加(たった25%)に対し書き込みコストは「実に15倍超」悪化している点が衝撃的です。
“なんとなく”の常識に惑わされないために:著者の総括
私個人の見解としても、RDB設計やDBチューニングの経験上、インデックス設計は「バランス感覚」が命です。
“SELECTが一瞬で終わる神DB”を目指しがちですが、その恩恵を受けるクエリ自体の頻度や事業インパクトに見合うかを常に再考すべきです。
インデックス本数=悪ではなく、“むやみに張ること”が悪、なのです。
また最近のPostgreSQLはハードウェア進化やアルゴリズム最適化の恩恵も受けており、数本程度のB-treeインデックスは今や大半の構成環境で十分許容範囲といえるでしょう。
むしろ「どの列に、どんな形で付けるべきか?」「複合・部分インデックスでどこまで省力化できるか?」という設計視点こそが現場で差を生むポイントです。
そして、“インデックス設計の善し悪しは、必ずや自分のテーブル・データ量・実データで検証すること”― これは記事筆者も強く提案しています。
“your mileage my vary, do your tests, but don’t be afraid to add small btree index every now and then 🙂”
つまり、「現実の負荷は実測しないことには分からない」「小規模なテスト表やダミーデータでしっかり予行演習を!」というわけです。
迷ったら検証!インデックス運用の勘所とは
本記事と元の記事の検証を踏まえ、以下の視点・アクションを推奨したいと思います。
- やみくもなインデックス増設は避ける一方、クエリ頻度や事業・システム要件を冷静に分析し、必要なものには思い切って投入することが肝心です。
- 必ず「実データ」および「本番に即した手元環境」で書き込み性能を測り、“コスト感”をリアルに把握しましょう。
- 複合インデックスや部分インデックス活用で“効きをよくしつつ、無駄を省く”省エネ運用を意識しましょう。
- GINや他の高コストインデックスは“安易に増設しない“徹底した検証が必須!
- 迷ったらまず小テスト!テーブル作成・100k投入・インデックスON/OFFで測定するだけでも大きな気づきが得られます。
インデックス設計と性能チューニングは、システムの成長とともに“見直され続けるべきもの”です。
今回の実証データや具体的な運用ノウハウから、ぜひみなさんのDB設計・運用現場に新たな視点と気づきを持ち帰っていただきたいと思います。
categories:[technology]


コメント