ひとのSQLを読むのが難しい

ずっともやもやとした課題感がある。 業務システム内で発行されるクエリであれば、だいたいは発行されるクエリまで考えてテーブル設計をするのでそこまで苦労しない(ポリモーフィズムenumが多用されてると結構きついこともあるけど)。一方でビジネスKPIや分析用のSQLになると難しいなと思っている。500行とかあると脳みそを使い果たして他の仕事ができなくなるくらいに疲れる。
だから、SQLのレビューがあまり好きではなく、後回しにしてしまう。
自分で書いたクエリは、日が空いても自分は読めるのだけど、やはり他の人にとっては読みにくそうなのがずっと不思議に思っていて、どうすれば他の人の書いたSQLを楽に読めるのか、少し向き合ってみる。

可読性を上げる

調べると多く出てくるのはこれだと思う。予約語の大文字小文字を統一しよう、とか。大文字と小文字の統一の話でいうと、慣習に従って大文字で統一するケースが多そう*1
ただ、個人的にはどうでもいい。SQLクライアントは予約語シンタックスハイライトくらいしてくれる。句ごとに行を分けるだけで充分効果はある。予約語を書くときだけ入力を大文字に切り替えるコストのほうがずっと高いと思う。書く側の気持ちになると、予約語を大文字で書くのはめんどくさすぎる*2*3
SELECT句のカンマをどこに置くかも似たような話で、読むという点においてはどっちでも良い。書く際は前カンマのほうが書きやすいと思うけど(最後にカンマがあると構文解析でエラーになるから)。
ただ、ASでつける名前は改善の余地があると思うことが多い。平気でtmpとつけたり、よくわからない略語や数字を使ったりする。たしかに、データを細かく整形するだけの中間状態みたいなものを挟むことはあるのだけど、なにげに結構つらいと感じる時がある。

クエリの最後から読む

今さらかと思うのだけど、最近気がついたのがこの方法。クエリの要件を確認してレビューなどに入ると、つい一つ一つの条件に気を取られてしまう。「何日以降」とか「ステータスがXX」とか。条件はSQLのそこかしこに散りばめられているので、要件を追うようにSQLを読むとかなりしんどいと最近気がついた。
クエリの最後から読むのは、プログラミングで言えばmain関数から読むという感覚。何をしたいのかの全体像をまず把握する。最終的に欲しいデータがなにか、そのデータを取得しているテーブルはどれか、という風にmainから順を追って読んでいくと割と素直に読みやすい気がする。この順で読むと「この問合せ要らなくない?」とかに気づきやすいように思う。

サブクエリを分割する

困難は分割する。よく言われていることなので、それだけ。WITH句やVIEWを使って目的ごとにテーブルを分割していく。分割していくと、特定のサブクエリごとの確からしさの検証などができるので信頼性も高くなる。結果的に、細かい条件のミスなどに気が付きやすいと思う。
ただ、この作業の中でもとのSQLを壊してしまうと悲しくなる(僕は分割することに夢中になってしまって壊すことがよくある)。

メンタルモデルを身につける

SQLを学び始めた頃はEXIST句やサブクエリ系は動作をパッと理解するのが難しかった。分析用のクエリだとLEFT JOIN時の歯抜けデータをCOALESCEで0埋めするとかもよくやると思う。データの縦持ちと横持ちを入れ替えるとかも・・
特にDWHに対してクエリを発行する際の時刻の扱いは苦しくて、DWHを実装する人がある人は頑張ってtimestamp型に変換したりある人が諦めて全部string型で突っ込んだりすると泣く。raw dataが良くないということもある。(ただこのあたりは自分の記憶が数年前なので最近は違うのかも) いずれにせよ、ある特定の部分を読んでぱっと理解できるというのは大事で、経験の積み重ねがモノを言うところだと思います。

ドメイン知識を身につける

結局は、当たり前だけどこれ。なぜそのデータがそのテーブルに格納されているのか。そのテーブルの意図するものは、そのカラムの意図するものはなんなのか。CRUDはどんなケースで発生するのか。…書いていて気付いたけれど、そもそもドメイン知識がないとレビューはできないですね。。

*1:大文字で統一してキャッシュがどうのこうの、という記事も見かけるけど本当なのだろうか

*2:気になるならIDEとかのformatterを使うのが良さそう

*3:そういえばAmazon Athenaにはオートフォーマットがあった。けど凄い変なフォーマットだった記憶がある