SQL Order of Operations – In Which Order MySQL Executes Queries?
Click to start, for free.
SQL クエリの操作順序のビットとバイトを知ることは、新しいクエリを書くプロセスを容易にし、また、SQL クエリを最適化しようとするときに非常に有益です。
簡単に説明すると、これは SQL クエリの論理的な操作順序であり、実行順序としても知られています。
- from, JOINを含む
- WHERE
- GROUP BY
- HAVING
- WINDOW関数
- SELECT
- DISTINCT
- UNION
- ORDER BY
- LIMIT and OFFSET
しかし、現実はそれほど簡単でもないし、単純でもない。 先に述べたように、標準SQLは異なるSQLクエリ句の実行順序を定義しています。 とはいえ、最近のデータベースは、実際の実行順序を変更するような最適化トリックを適用することにより、すでにそのデフォルトの順序に挑戦していますが、デフォルトの実行順序でクエリを実行していた場合と同じ結果を返すようにしなければなりません。 データベースが WHERE 句とそのインデックスを調べる前に、まず FROM 句 (JOIN を含む) で言及されているすべてのデータをフェッチするとしたら、それは愚かなことでしょう。 5340>
SQL クエリの各部をその実行順序に従って見てみましょう。
FROM と JOIN
FROM 句 (JOIN を含む) で指定したテーブルが最初に評価され、クエリーに関連する作業セット全体が判断されます。 データベースは、JOINs ON句に従ってすべてのテーブルからデータを結合し、同時にサブクエリからデータをフェッチし、さらにこの句のサブクエリから返されたデータを保持するためにいくつかの一時テーブルを作成する可能性もあります。
しかし、多くの場合、データベースのオプティマイザは、作業セットのどの部分を省くことができるか (できればインデックスを使用して) を確認するために、最初に WHERE 節を評価することを選択し、本当に必要ない場合はデータセットをあまり膨らませないようにします。 これらの条件には FROM 句からのデータとテーブルへの参照を含めることができますが、SELECT 句で定義されたエイリアスへの参照は含めることができません。
また、WHERE 句の一般的な落とし穴は、たとえば次の句のように、WHERE 句で集計値をフィルタリングしようとすることでしょう。 「WHERE sum(available_stock) > 0 “とします。 なぜなら、集約はプロセスの後半で評価されるからです(下記のGROUP BYセクションを参照してください)。 集計されたデータにフィルタリング条件を適用するには、WHERE句ではなくHAVING句を使用する必要があります。
GROUP BY句
さて、WHERE句を使ってデータセットをフィルタリングしたので、GROUP BY句に現れる1つまたは複数の列に従ってデータを集計することができます。 データのグループ化は、実際にはデータを異なるチャンクまたはバケットに分割し、各バケットには1つのキーとそのキーに一致する行のリストがあります。 GROUP BY 句を使用しない場合、すべての行を 1 つの巨大なバケツに入れるようなものです。
データを集約したら、集約関数を使用して、各バケツについてグループごとの値を返すことができるようになりました。 このような集約関数には、COUNT、MIN、MAX、SUMなどがあります。
HAVING 節
GROUP BY 節を使ってデータをグループ化したので、HAVING 節を使っていくつかのバケットをフィルタリングすることができます。 HAVING句の条件は集約関数を参照することができるので、上のWHERE句でうまくいかなかった例も、HAVING句ではうまくいきます。 「HAVING sum(available_stock) > 0″.
すでにデータをグループ化しているため、この時点で元の行にはアクセスできません。したがって、バケット全体をフィルターする条件のみを適用し、バケット内の単一の行はフィルターできません。
また、以前のセクションで述べたように、SELECT 句で定義されたエイリアスは、まだデータベースによって評価されていないため、このセクションでもアクセスできません (これはほとんどのデータベースで当てはまります)。
ウィンドウ関数
ウィンドウ関数を使っている場合、この時点で実行されることになります。 グループ化機構と同様に、Window関数も行の集合に対して計算を実行します。 主な違いは、Window 関数を使用する場合、各行は独自の ID を保持し、他の類似した行のバケットにグループ化されないことです。
Window 関数は、SELECT 節または ORDER BY 節のいずれかでのみ使用可能です。 Window 関数の内部で集約関数を使用できます。たとえば、
SUM(COUNT(*)) OVER ()
SELECT 節
データセットからの行の破棄とデータのグループ化が終わったので、クエリーからクライアント側に取り出したいデータを選択することができるようになりました。 SELECT 句の内部では、列名、集約、およびサブクエリを使用できます。 SELECT句の中でCOUNT(*)のような集約関数への参照を使用している場合、それはグループ化が行われたときに既に発生した集約への参照に過ぎないので、集約自体はSELECT句の中では発生せず、これはその結果セットへの参照でしかないことを覚えておいてください。
DISTINCT キーワード
DISTINCTキーワードの構文は、SELECT句の列名の前にキーワードが位置するため、少し分かりにくくなっています。 しかし、実際の DISTINCT 操作は SELECT 節の後に行われます。 DISTINCT キーワードを使用すると、データベースは、フィルタリングと集約が行われた後に残った行から、重複する値を持つ行を破棄します。
UNION キーワード
UNIONキーワードは、2つのクエリの結果セットを1つの結果セットにまとめます。 ほとんどのデータベースでは、UNION DISTINCT(結合された結果セットから重複する行を破棄する)またはUNION ALL(重複チェックを適用せずに結果セットを結合するだけ)のいずれかを選択することができます。
UNION の結果セットに対して、通常のクエリと同様に、ソート(ORDER BY)と制限(LIMIT)を適用できます。
ORDER BY 句
ソートは、データベースが結果セット全体を準備した時点で行われます(フィルタリング、グループ化、重複の除去を行った後)。 それができると、データベースは、列、選択されたエイリアス、または集約関数を使用して、たとえそれらが選択されたデータの一部でなくても、結果セットをソートすることができるようになります。 唯一の例外は DISTINCT キーワードを使用するときで、選択されていない列でソートすることはできません。その場合、結果セットの順序は不定になります。
降順 (DESC) または昇順 (ASC) を使用してデータをソートすることを選択できます。 順序は順序の部分ごとに一意であることができるので、次のようなものが有効です。 ORDER BY firstname ASC, age DESC
LIMIT と OFFSET
ほとんどのユースケース(レポート作成など一部を除く)では、クエリの結果の最初のX行以外のすべての行を破棄したいと思うでしょう。 LIMIT句はソートの後に実行され、まさにそれを可能にします。 さらに、LIMITとOFFSETキーワードを組み合わせることで、どの行からデータを取得し、何行を除外するかを選択することができます。 次の例は、100 番目の行から 50 行を取得します: LIMIT 50 OFFSET 100
Click to start, for free.