「全部見なくていいよ!」をデータベースに伝える魔法の呪文
こんにちは!日々のデータベース運用、お疲れ様です。
PostgreSQLを使っていると、「あれ、このクエリ、なんでこんなに時間がかかってるの?」と首をかしげたくなること、ありますよね。
特に、データが数百万件、数千万件と増えてくると、データベースは「よし、全部のデータを一生懸命調べてくるぞ!」と気合を入れすぎて、逆に動きが鈍くなってしまうことがあります。
今日はそんな時に役立つ、ちょっとマニアックだけど知っておくとカッコいい設定「`cursor_tuple_fraction`」についてお話ししますね。
—
「全部読みますか?」という問いかけ
想像してみてください。あなたは巨大な図書館の司書さんです。
誰かがやってきて、「この図書館にある本の中で、一番最近入荷した10冊を教えて!」と言いました。
普通なら、新しい順に並んでいるリストの「最初の方だけ」を確認すればいいですよね?
でも、PostgreSQLは真面目すぎる性格なんです。
「一番新しい10冊? 了解! じゃあ、とりあえず図書館にある全データ(数百万冊)を最初から最後まで全部リストアップしてから、その中から上位10冊を選びますね!」
……いやいや、そこまでしなくていいよ!って言いたくなりますよね。
cursor_tuple_fraction って何者?
この「全部調べるか、途中で切り上げるか」をデータベースに教える設定値が `cursor_tuple_fraction` です。
デフォルトでは「0.1(10%)」という値が入っています。「とりあえず10%くらいは調べるのが普通だよね?」という基準なんですが、実はこれ、「最初からほんの少しだけ欲しい」という時には、ちょっと多すぎることが多いんです。
この値を小さく設定してあげると、データベースはこう考えます。
「お、今回はそんなに全部を見なくていいんだね。じゃあ、重たい『全件並べ替え』みたいな処理は一旦やめて、もっと速く結果を出せる方法(インデックスを使うなど)に切り替えよう!」
—
具体的にどう設定するの?
この設定は、システム全体で変えることもできますが、まずは「特にこのクエリだけ速くしたい!」という時に、そのクエリの直前で実行するのがおすすめです。
— PostgreSQLの賢い子に「全部見なくていいよ」と教える
SET cursor_tuple_fraction = 0.0001;
— 実際にやりたいクエリを実行
SELECT FROM huge_table ORDER BY created_at DESC LIMIT 10;
こうすることで、データベースのプランナー(計画を立てる担当)が、「あ、じゃあ全件走査するのはやめて、インデックスをうまく使って最初の方だけササッと取ってこよう」と判断してくれるようになります。
—
注意点:魔法の杖ではないんです
もちろん、何でもかんでもこの値を小さくすればいいというわけではありません。
もし「結局、全件読み取るクエリ」なのにこの値を小さくしてしまうと、データベースは「最初だけ速く取れればいいや」という作戦をとるため、後半のデータを取り出す時にかえって効率が悪くなるという本末転倒なことが起こります。
- LIMIT句などで最初の方だけ欲しい時
- カーソルを使って少しずつデータをフェッチ(取得)する時
こういう「全部は見ないよ」というシチュエーションでこそ、この魔法が輝くんです。
おわりに
データベースのチューニングって、まるで料理の隠し味みたいですよね。
「ちょっとだけ設定を変えるだけで、こんなに味が変わるの?」という発見が、この仕事の醍醐味だったりします。
もし、皆さんのシステムで「LIMITをつけているのに、なぜかスキャンが止まらない……」という謎の現象に遭遇したら、ぜひこの `cursor_tuple_fraction` を思い出してみてください。
現場からは以上です!また次の記事でお会いしましょう。質問などあれば、いつでもコメント欄で教えてくださいね!
コメント