【リーダブルSQL】のススメ〜「動いたからいいや」が口癖のあなたへ〜
1. はじめに
株式会社Hogetic Labの古畑です。
突然ですが、皆さんは「他人が書いたSQLクエリ、読みにくいな…」と思ったことはありませんか?
さらに、他人のクエリを読み解くのが面倒で、つい自己流に書き直してしまった経験はないでしょうか?
「変な改行や大文字・小文字の混在で、構造が掴みにくい」「サブクエリが多すぎて、頭がこんがらがる」「そもそも、このクエリが何を意図しているのか、まったくわからない」――こんな経験をしたことがある方も多いと思います。
# 読みにくいクエリの例
select game_id, user_id FROM
game_access where date = "2024-01-01"
AND user_id = 12345678
個々人の“流儀”に従って作成されたクエリは読みにくく、結果としてレビューにかかる時間を増やし、生産性を低下させる要因となります。
この記事では、新卒から6年間データアナリストとしてSQLを書き続けてきた私が、クエリ作成やレビューの際に意識しているポイントを紹介します。また、弊社で実際に採用しているルールを1つのリーダブルな例としてご紹介したいと思います。
前提
- 実行環境はBigQuery(Google Cloud Platform)を想定しています
- お使いの環境によっては、参考例が動作しない可能性もあります
- 想定読者は若手のデータアナリストなど、短時間で大量のクエリを書く必要のある人を想定しています
- クエリレビューを中心にされる方は適宜読み替えて下さい
- クエリのルールについて、唯一絶対の”正解”は存在しません
- すでに所属組織の規則が決まっている場合には、そちらに合わせてください
2. リーダブルコードとリーダブルSQL
そもそも、読みやすいクエリ・読みやすいクエリとは何なのでしょうか?
それを理解するために、「リーダブル(readable)」という概念について考えてみたいと思います。
「エンジニアが読むべき本」のような話題になると絶対と言っていいほど挙げられる良書に『リーダブルコード』があります。
書籍名の通り、良いコードを書くためのシンプルで実践的なテクニックを提供している一冊です。
内容をまとめると、本書では優れたコードを「他の人が読んだ時に、意味を理解するまでの時間を短くできるコード」と定義しています。
リーダブルコードの思想は、主に以下の2つです。
- コードは他の人が最短時間で理解できるように書かなければならない
-
コードは短く書いたほうがよいが、「理解するまでの時間が短くなる」ほうが優先度は高い
- 短く書くことによって、他の人が読んだ時に理解に苦しむ(理解に時間がかかる)ようなコードは本末転倒
この思想は、SQLクエリにも同様に適用できると思います。
この思想にのっとったSQLクエリを、本記事では便宜的に「リーダブルSQL」と呼ぶことにします。
-
クエリは他の人が最短時間で理解できるように書かなければならない
- 「書きやすい(=とりあえず動けばいい)」クエリと、「読みやすい(=レビューしやすい)」クエリは別物
-
クエリは短く書いたほうがよいが、「理解するまでの時間が短くなる」ほうが優先度は高い
- 複雑な条件式やサブクエリの複雑な入れ子構造、マジックナンバーは使わない方が良い
3. リーダブルSQLのメリット
前述の通り、「書きやすい」クエリと「読みやすい」クエリは異なります。
そして直感の通り、書き終わるまでの時間が短いのは「書きやすい」クエリです。
では、なぜリーダブルSQLを採用する必要があるのでしょうか?
リーダブルSQLには、以下のようなメリットがあります。
-
クエリは「作成して終わり」でなく、今後の資産になるから
- 作成したクエリにミスが見つかったり、後から集計条件が変更されることはよくあります
- 該当箇所の発見・修正を早く行えるようなクエリを書く必要があります
-
クエリを書く際の思考がクリアになるから
- 集計作業に集中できるため、クエリを書く際のロジックミスを削減することができます
- ミスの発見もしやすくなるので、レビューに回す前に自分でミスに気づきやすくなります
-
未来の後輩に業務を引き継ぎやすいから
- 集計の仕様を知りたいとき、頼りになるのはいつ更新されたかわからないドキュメントよりも運用されているクエリそのものです
- 未来のチームメンバーや数年後のあなたが失望/絶望しないようなクエリを書く必要があります
アナリストは職位が上がるにつれ、クエリを書く時間よりも読む時間の方が長くなっていきます。
未来の自分を助けるためにも、リーダブルSQLを心がけていくことをオススメします。
4. リーダブルSQLのコツ4選
ここからは実例とともに、リーダブルSQLのコツを4つ挙げていきます。
どれが正解という訳でもなく、流派が多くあるかと思いますが、以下弊社でのルールをご紹介したいと思います。
① 予約語と変数・テーブル名は改行、WHERE句は1行に1条件
適切な改行を行うことで、クエリの視認性が上がります。
# いまいちな例
SELECT game_id, user_id FROM
game_access WHERE date = "2024-01-01"
AND user_id = 12345678
# 良い例
SELECT
game_id,
user_id
FROM
game_access
WHERE
date = "2024-01-01"
AND
user_id = 12345678
② 予約語/データ型/関数は大文字、変数名は極力小文字
予約語を大文字に、変数名を小文字にすることで、構造が理解しやすくなります。
# いまいちな例
select
game_id,
count(user_id) as user_num
from
game_access
where
date = "2024-01-01"
group by
1
# 良い例
SELECT
game_id,
COUNT(user_id) AS user_num
FROM
game_access
WHERE
date = "2024-01-01"
GROUP BY
1
③ 適切なインデント・スペースの付与
適切にインデント・スペースを付与することで、クエリの視認性を上げることができます。
- インデントはスペースでなくTabを用いる
- SELECT, FROM, ORDER BY, HAVING等はインデントを揃える
- 予約語よりカラム名/テーブル名を1つインデント
- AND・ORはカラム名/テーブル名と揃える
- 行中のカンマの後にスペース
- 変数名と「=」などの記号の間にスペース(「>=」「<=」は1文字扱い)
# いまいちな例
SELECT
game_id,
user_id,
SUBSTR(date,1,7) AS month
FROM
game_access
WHERE
date>="2024-01-01"
AND
user_id=12345678
# 良い例
SELECT
game_id,
user_id,
SUBSTR(date, 1, 7) AS month
FROM
game_access
WHERE
date >= "2024-01-01"
AND
user_id = 12345678
④ サブクエリは使わない
サブクエリは入れ子構造になるため、直感的に理解しづらく記載ミスが増えます。
多少冗長でもWITH句を使用した方が、可読性が高く確認しやすくなります。
# いまいちな例
SELECT
*
FROM
daily_user
WHERE
user_age >=
(
SELECT
AVG(uu) AS average_uu
FROM
daily_user
)
# 良い例
WITH
avg_uu AS (
SELECT
AVG(uu) AS average_uu
FROM
daily_user
)
SELECT
*
FROM
daily_user
CROSS JOIN
avg_uu
WHERE
average_uu <= user_age
5. まとめ
今回は「リーダブルSQL」を作成するメリットとその実例について解説しました。
改めて、私がリーダブルSQLを通じて大切にしているのは以下の2点です。
- 他人が読んだ時に、クエリの中身を把握するまでの時間を短くすること
- 書いたクエリが自分の手を離れても、運用に支障が出ないこと
リーダブルなSQLを書くことは、単に「見やすさ」を追求するだけでなく、プロジェクト全体の効率と生産性を高める重要な要素です。
データ活用がますます進む時代において、リーダブルSQLはチーム全体の成長を支える重要なスキルとなると思います。
最後に宣伝ですが、弊社はGoogleの生成AIパートナーとして、Google Cloudの活用およびデータ分析の民主化に取り組んでいます。
データアナリスト・データエンジニアをはじめ各ポジションでの採用も行っておりますので、ご興味がある方はチェックしてみてください。
Discussion