5月14日、著者が「SQL's ORDER BY Has Come a Long Way」と題した記事を公開した。この記事では、SQLのORDER BY句の進化史とその技術的な変遷について詳しく紹介されている。以下に、その内容を紹介する。
1980年代の制約だらけなORDER BY
1980年代のORDER BY句には4つの大きな制約があった。(1)SELECT句で選択された列にしか参照できない、(2)式(expression)が使用できない、(3)NULL値の順序を直接制御する構文がない、(4)クエリの最後の句としてのみ使用可能、という制約だ。
例えば、以下のクエリはISO/IEC 9075-2:1999まで無効だった:
SELECT a
FROM t
ORDER BY b -- 選択されていない列bでソートしようとしている
なぜ選択されていない列でソートできなかったのか。それはSQLの論理的評価順序に起因する設計上の問題だった。
3つの「順序」:構文・論理・実際の実行
記事では、SQLには3つの異なる順序概念が存在することを指摘している。
構文順序は文中の句の順番(SELECT、FROM、ORDER BY)で、論理的評価順序は標準が定める処理の流れ(FROM → SELECT → ORDER BY)だ。上記のクエリが無効だった理由は、FROM句が表tの全内容(列bを含む)を作成し、SELECT句がそれを列aのみに絞り込むため、ORDER BY句が受け取る時点では列bが存在しないからだ。
しかし最も重要なのは3つ目の「実際の実行順序」である。SQL標準にはこんな記述がある:
準拠するSQL実装は、一般規則で定義された正確な動作シーケンスを実行する必要はなく、その効果が同一である限り問題ない
— ISO/IEC 9075-1:2023 §6.3.3.3
つまり、結果が同じであれば実装は自由にクエリを最適化してよい。「早期フィルタリング」のマントラも、実際の実行順序には正しいが、構文や論理順序に適用するのは無意味だということになる。
SQL:1999の「ビッグバン」
1999年12月に公開されたSQL:1999は「モダンSQLのビッグバン」と呼ばれる大変革だった。boolean型からCTEまで、数多くの新機能が追加されたが、ORDER BY句も大幅に改良された。
最大の変更は非選択列の使用が可能になったことだ。これは構文変換(syntactic transformation)という仕組みで実現された。ORDER BY句が非選択列を参照すると、標準はその列を一時的にSELECT句に追加し、ORDER BY処理後に再び除去する。「関心の分離を情け容赦なく破る」設計だが、目的のためには手段を選ばないアプローチだ。
式の対応とNULL順序制御
SQL:1999ではORDER BYで任意の式が使用可能になった。ただし、現在でも一部のDBMSは完全な式対応ができていない:
-- これは全システムで動作
SELECT a + b
FROM t
ORDER BY COALESCE(a + b, 0)
-- これは一部システムで失敗
SELECT a + b AS x
FROM t
ORDER BY COALESCE(x, 0)
2003年にはNULL値の順序制御が追加された:
SELECT a
FROM t
ORDER BY b NULLS FIRST
これがないと、NULL値の位置は実装依存になってしまう。
サブクエリでのORDER BY解禁
元々ORDER BYはサブクエリで使用できなかった。これはSQLが集合論に基づいており、集合には順序がないという思想によるものだった。
しかし2008年にFETCH FIRST句(LIMITのより強力な版)が導入されると状況が変わった。FETCH FIRSTをサブクエリで意味を持たせるには、ORDER BYが必要だったからだ。特にLATERAL JOINでの用途で重要性が高まった。
現在ORDER BYは、window関数のOVER(ORDER BY)、MATCH_RECOGNIZE(ORDER BY)、JSON_ARRAYAGG(ORDER BY)など様々な場所で使用されている。
エンジニアにとっての教訓
この進化史から得られる重要な教訓は、実行計画を信じろ、インフォグラフィックを信じるなということだ。SQLエンジンは数十年にわたって自動最適化を行っており、開発者が手動で「最適化」しようとする必要はない。
ORDER BY句の歴史は、SQLが単純な関係モデルから現実的な要求に応えるツールへと進化した過程を象徴している。制約から自由へ、理論から実用性への変遷といえるだろう。
詳細はSQL's ORDER BY Has Come a Long Wayを参照していただきたい。