# ディスカッション
PostgreSQL 18の新機能「B-treeインデックスのスキップスキャン」
**ずん
** データベースが8倍速くなったって、もしかしてこれ人類史上最大の発明なのだ?
**でぇじょうぶ博士
** やんす。まあ、火の発見や車輪の発明には及ばないでやんすけどね。でもこのスキップスキャン機能、複合インデックスの使い方を根本から変える可能性があるでやんす。
**やきう
** はいはい、またデータベースオタクが騒いどるわ。ワイらには関係ない話やろ。
**でぇじょうぶ博士
** そんなことないでやんす!今まで、複合インデックスってのは先頭の列がWHERE句にないと使えない、まるで鍵穴に鍵を最初から全部差し込まないと開かない金庫みたいなもんだったでやんす。
**でぇじょうぶ博士
** まあ、PostgreSQL 17まではそうでやんすね。顧客IDだけで検索すると、性別の列をスキップできず、テーブル全体をスキャンする羽目になってたでやんす。
**やきう
** それでストレージ代ケチれるんやな。ええこっちゃ。
**でぇじょうぶ博士
** そうでやんす。スキップスキャンは、先頭列の全パターンに対して動的に等価制約を生成するでやんす。つまり、WHERE 顧客ID = 100 だけ指定しても、内部的には WHERE 性別 = '男' AND 顧客ID = 100、WHERE 性別 = '女' AND 顧客ID = 100 みたいに勝手に分解して探すでやんす。
**ずん
** それって、結局全部探すのと同じなのだ?意味ないじゃん。
**でぇじょうぶ博士
** 違うでやんす!先頭列のカーディナリティ(値の種類)が少ない場合、例えば性別なら2種類、都道府県なら47種類だけでやんす。100万件のテーブルを全部見るより、2回や47回の検索の方が圧倒的に速いでやんす。
**やきう
** なるほどな。でも先頭列の値が多かったらどうなんや?
**でぇじょうぶ博士
** それは鋭い指摘でやんす。もし先頭列が顧客IDのようにカーディナリティが高いと、逆に遅くなる可能性があるでやんす。だから、複合インデックスの設計では先頭に低カーディナリティの列を置くのがベストプラクティスになるでやんす。
**ずん
** じゃあボク、全部のインデックスを(性別
**でぇじょうぶ博士
** それはバカでやんす。インデックスは万能薬じゃないでやんす。更新時にはインデックスのメンテナンスコストがかかるし、ディスク容量も食うでやんす。必要な分だけ作るのが鉄則でやんす。
**やきう
** でもこれ、実行計画見てもスキップスキャンしてるか分からんって書いてあるやん。ホンマに動いてんのか?
**でぇじょうぶ博士
** 確かに、実行計画には明示的な表記がないでやんすね。でも検証結果を見れば一目瞭然でやんす。PostgreSQL 17では2.220ms、18では0.276msで、約8倍の性能向上が確認されてるでやんす。これはスキップスキャンが機能している証拠でやんす。
**ずん
** つまり、PostgreSQL 18にアップグレードすれば、ボクの給料も8倍になるってことなのだ?
**やきう
** なるかい。お前の脳みそこそスキップスキャンが必要やわ。
**ずん
** むぅ...じゃあせめて残業時間が8分の1になればいいのだ!
**でぇじょうぶ博士
** それは...クエリの応答速度とは別問題でやんす。でも、データベースの性能が上がれば、バッチ処理やレポート生成が速くなって、結果的に残業が減る可能性はあるでやんす。
**やきう
** ほな早速導入するかと思ったけど、またアップグレード作業で残業やん。本末転倒やわ。
**ずん
** でも18.625msのSeq Scanが18.132msになってるのって、むしろ遅くなってないのだ?
**でぇじょうぶ博士
** 細かいところまで見てるでやんすね。これは試行回数が少ないので誤差の範囲でやんす。Seq Scanは基本的にバージョンによる大きな違いはないはずでやんす。重要なのは、Index Scanとの比較でやんす。
**やきう
** つまり、Seq Scanとの差が67倍から2倍になったってことか。これはデカいな。
**でぇじょうぶ博士
** その通りでやんす。そしてPostgreSQL 18からは、EXPLAIN ANALYZEで自動的にバッファ使用量が表示されるようになったのも地味に便利でやんす。17まではBUFFERSオプションを付ける必要があったでやんす。
**ずん
** バッファって、牛の肉みたいなやつなのだ?
**やきう
** それバッファローや。お前、ホンマにエンジニアか?
**でぇじょうぶ博士
** バッファはメモリ上のキャッシュ領域のことでやんす。データベースがディスクから読み込んだデータを一時的に保管する場所でやんす。これを見ることで、クエリがどれだけメモリを効率的に使っているか分かるでやんす。
**ずん
** じゃあ、バッファをたくさん食べれば頭が良くなるのだ!
**やきう
** もうええわ。お前はバッファローの肉でも食っとけ。
**ずん
** そんなことより、この記事100万件のデータでテストしてるけど、ボクの会社なんて顧客100人しかいないのだ。関係ないじゃん!
**でぇじょうぶ博士
** 100人...それはもはやExcelで十分でやんす。でも将来的にスケールする可能性を考えると、今のうちから効率的なインデックス設計を学んでおくのは重要でやんす。
**やきう
** 100人の顧客で100万件のデータって、一人あたり1万レコードやん。どんなビジネスしとんねん。
**ずん
** えっと...ログデータとか?(適当)
**でぇじょうぶ博士
** まあ、IoTデータやアクセスログなら十分あり得る数字でやんす。重要なのは、データ量に応じた適切なインデックス戦略を立てることでやんす。
**やきう
** で、結局どんな時にこのスキップスキャンが有効なんや?
**でぇじょうぶ博士
** 簡単に言うと、こんな条件の時でやんす。
1. 複合インデックスの先頭列がWHERE句にない
2. 先頭列のカーディナリティが低い(値の種類が少ない)
3. 2番目以降の列に対する条件がある
具体例なら、注文テーブルで(注文ステータス
**やきう
** 「ずん」って顧客IDに入れるなや。普通数字やろ。
**でぇじょうぶ博士
** まあ、それはともかく、理解は正しいでやんす。ただし、先頭列の値が増えれば増えるほど効果は薄れるので、設計時には注意が必要でやんす。
**ずん
** じゃあ、PostgreSQL 18に今すぐアップグレードするのだ!
**やきう
** ちょっと待てや。本番環境でいきなりメジャーバージョンアップとか正気か?まず検証環境で試すのが常識やろ。
**でぇじょうぶ博士
** その通りでやんす。PostgreSQLのメジャーアップグレードは、互換性の問題やその他の変更点も含めて慎重に検証する必要があるでやんす。記事でもDockerを使って検証してるのは、そういう理由でやんす。
**ずん
** むぅ...じゃあボクは検証環境でテストするフリをして昼寝するのだ!これがスキップスキャンの真髄なのだ!