DO’s&DONT’s #13: 絶対にやってはいけないこと – ORDER BY が指定されていないクエリの結果が一定の順番に並んでいると仮定すること


 

神谷 雅紀
Escalation Engineer

 

多くの場所で議論されている場面を見かけるため、ここで明確にしておきたいと思います。

 

ORDER BY のない SELECT の実行結果内の行の並び順は一切保証されない

SELECT の実行結果の並び順が保証されるのは、最も外側 (最も上位) の SELECT に ORDER BY が指定されている場合だけです。

SELECT 内のサブクエリ内に ORDER BY が指定されていたとしても、また、ビューの中で ORDER BY が指定されていたとしても、それらを参照する最も外側の SELECT に ORDER BY が指定されていなければ、SELECT の実行結果内の行の並び順は不定です。

これは、クラスタ化インデックスがあるかどうか、非クラスタ化インデックスがあるかどうか、並列クエリであるのかどうか、どのような順番で行が INSERT されたかなど、いかなる要因にも左右されません。どのような場合であっても、SELECT の実行結果の並び順が保証されるのは、最も外側の SELECT に ORDER BY が指定されている場合だけです。

もし ORDER BY を指定していない SELECT の結果が期待した順番に並んでいたとしても、それに依存してアプリケーションやシステムを設計、実装、構築しないで下さい。期待する並び順があるのであれば、必ずそれを ORDER BY として指定することで、並び順を SQL Server に指示しなければいけません。SQL Server があなたの期待を察して並べてくれることを期待しないようにして下さい。

 

ビュー内の ORDER BY 指定はビューに対する SELECT 結果の並び順には作用しない

通常、ビュー内の SELECT には ORDER BY を指定することができません。しかし、ビュー内の SELECT であっても TOP が指定されている場合は、ORDER BY を指定することができます。TOP と共に使用される ORDER BY は、ビュー内で指定されている SELECT 結果を ORDER BY の指定順に並べた後に上位 n 行を取り出すことを指定するものであり、ビューに対する SELECT の実行結果の行の並び順には全く作用しません。

これは、[FIX] SQL Server 2008 で ORDER BY 句を使用したビューを使用してクエリを実行しても結果がランダムな順序で返されるに示されている更新プログラムを適用した場合であっても同様です。

TOP 100 PERCENT と ORDER BY が同時に指定された場合、ORDER BY 順に並べなおさなくても TOP の指定を満たすことができることから (並べなおしても並べなおさなくてもすべての行が対象であることから)、クエリパフォーマンスを考慮し、SQL Server 2008 では、クエリの単純化 (simplification) 処理の一部として、ビュー内の SELECT から無駄な処理となる ORDER BY を削除するようにしました。

しかし、一部のコミュニティや Blog で紹介されていたことが原因であると思われますが、ビュー内で TOP 100 PERCENT を指定することで ORDER BY 順に結果が返される場合があるという不確実な事象に依存した作りのアプリケーションが存在したために、それらアプリケーションの救済措置として、この更新プログラムでは、トレースフラグ 168 が指定されている場合のみ、ビュー内の SELECT から ORDER BY を削除しないようにしました。

ここで注意が必要なのは、更新プログラムを適用してトレースフラグを有効にしたとしても、ビュー内の SELECT から ORDER BY が削除されないだけであって、このビューに対する SELECT の実行結果がその ORDER BY 順に並ぶことは保証していないことです。

TOP 100 PERCENT 指定であっても ORDER BY を削除しなかった SQL Server 2005 以前であっても、SELECT の実行結果がその ORDER BY 順に並ぶことは保証していませんでした。前述のとおり、TOP とともに指定されている ORDER BY は、上位 n 行を選び出すために使用されるだけであるため、ビューに対する SELECT で GROUP BY が指定されていたり、ビューを他のテーブルと結合していたり、並列クエリとして実行されたりした場合などには、ビュー内の ORDER BY 順とそのビューに対する SELECT の実行結果内の並び順とは一致しませんでした。

 

GROUP BY と SELECT 結果の並び順

余談ですが、ビュー内の ORDER BY と同じような例として、GROUP BY がありました。古い話ですが、SQL Server 6.5 以前は、グループ化を行う唯一の実装が、GROUP BY 指定順にソートした後にグループ化することでした。今で言うと ORDER GROUP ヒントを指定した場合の動きです。そのような動作を行うため、GROUP BY を指定した SELECT 結果は GROUP BY に指定した順番に並んでいました。当然この並び順も保証されたものではありませんでした。しかし、この動きに依存したアプリケーションが存在したために、SQL Server 7.0 では、65 互換モードの場合には SELECT に ORDER BY が指定されていなくても、クエリ解析時に GROUP BY と同じ列指定で ORDER BY を内部的に付加し、結果が GROUP BY 順に並ぶようにしていました。

Comments (0)

Skip to main content