web-dev-qa-db-ja.com

この特定の冗長な派生テーブルの順序が保証されない可能性は本当にありますか?

TwitterとLukas Ederとの会話 でこの質問に遭遇しました。

正しい動作は、最も外側のクエリにORDER BY句を適用することですが、ここでは、最も外側のクエリでDISTINCT、GROUP BY、JOINまたはその他のWHERE句を使用していないため、RDBMSは単に内部クエリで並べ替えられた受信データ?

SELECT * 
FROM (
    SELECT * FROM table ORDER BY time DESC
) AS t

この例をPostgreSQLで実行すると、少なくとも、内部クエリとこの派生テーブルの例の両方で同じ実行プランが得られ、同じ結果セットが得られます。

つまり、プランナは最も外側のクエリを冗長にするか、単に内部のテーブルからの結果を渡すため、単純に破棄することを想定しています。

これはそうではないかもしれないと誰かが思いますか?

12
Vlad Mihalcea

ほとんどのデータベースは、サブクエリのORDER BYが次のいずれかであるという事実について非常に明確です。

  • 許可されない:例SQL Server、Sybase SQL Anywhere(TOPまたはOFFSET .. FETCHで補完されている場合を除く)
  • 意味がない:例PostgreSQL、DB2(ここでも、OFFSET .. FETCHまたはLIMITで補完しない限り)

DB2 LUWマニュアルの例を示します(強調は私のものです)

副選択のORDER BY句行の順序には影響しませんクエリによって返されます。 ORDER BY文節は、最も外側の全選択で指定されている場合に返される行の順序にのみ影響します。

表現は非常に明確です PostgreSQLのように

並べ替えが選択されていない場合、行は不特定の順序で返されます。その場合の実際の順序は、スキャンおよび結合プランのタイプとディスク上の順序に依存しますただし、これに依存することはできません。特定の出力順序は、ソートステップが明示的に選択されている場合にのみ保証されます。

この仕様から、派生テーブルのORDER BY句の結果の順序は偶然であり、偶然に予想される順序と一致する場合があります(これは自明な例のほとんどのデータベースで行われます)。これに頼るのは賢明ではありません。

DB2に関する補足:

特に、 DB2にはORDER BY ORDER OF <table-designator> と呼ばれるあまり知られていない機能があり、次のように使用できます。

SELECT C1 FROM
   (SELECT C1 FROM T1
      UNION
    SELECT C1 FROM T2
    ORDER BY C1 ) AS UTABLE
ORDER BY ORDER OF UTABLE

この特定のケースでは、派生テーブルの順序はexplicitlyの最外部のSELECTで再利用できます。

Oracleに関する補足:

長年にわたり、OFFSETを使用してROWNUMページネーションを実装することはOracleの慣習であり、合理的に計算できますafter派生テーブルの順序付け:

SELECT *
FROM (
  SELECT rownum AS rn, t.* -- ROWNUM here depends on the derived table's ordering
  FROM (
    SELECT * FROM table ORDER BY time DESC
  ) t
) t
WHERE rn BETWEEN 10 AND 20

少なくともクエリにROWNUMが存在する場合、将来のOracleバージョンでは、まだ移行されていないレガシーOracle SQLをほとんど壊さないように、この動作を壊さないことが合理的に期待できます。より望ましい、読みやすいSQL標準のOFFSET .. FETCH構文:

SELECT * FROM table ORDER BY time DESC OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY
20
Lukas Eder

はい。 ORDER BY句がないと、出力順序は定義されず、クエリプランナーは、これを知っていて理解していると見なすことができます。

特に、クラスター化されたインデックスがない場合や、順序付けをサポートするインデックスがまったくない場合は、外部クエリで順序が指定されていないため、並べ替え操作を回避するために内部クエリの順序を削除できる可能性があります。そうでない場合now将来のバージョンで実行される可能性があります。

未定義の動作に依存しないでください。特定の順序が必要な場合は、適切な場所にORDER BY句を指定します。

12
David Spillett

未定義の動作に関するそれ自体の問題-あなたのために働く、私のために働く、製品でHDDを再フォーマットする;)

一歩下がって、ある意味であなたは正しいと言えます。正気のRDBMSが内部のselectの行を再配置する地上の理由はありません。しかし、これは保証されていません。つまり、将来的には理由がある可能性があることを意味し、ベンダーは自由にそれを行うことができます。この動作に依存するコードは、API POVからの互換性のない変更ではないため、公開する義務がないベンダーの変更に翻弄されることを意味します。

6
PaulJWilliams

この特定の冗長な派生テーブルの順序が保証されない可能性は本当にありますか?

現在存在するすべてのPostgres(テストしていた)バージョンの答えは次のとおりです:No-この特定のクエリの場合。ソート順は保証されています。

MicrosoftはサブクエリでのORDER BYさえ許可していないため、SQLサーバーの人々はこれに不快になります。それでもPostgresのこの単純なクエリでは、ソート順が保証されています。 ORDER BYはサブクエリに適用され、外部クエリは順序を変更する可能性のあることは何もしません。

このマニュアルでは、章でも多くのことを示唆しています

あるいは、ソートされたサブクエリからの入力値の提供は通常は機能します。

これが当てはまるのは、外部のクエリレベルでは、順序を変更する可能性のある操作が追加されないことだけです。したがって、これは単純な場合にのみ「保証」され、SQL標準ではサポートされていません。 Postgresは、追加の操作が必要な場合は自由に再注文できます。疑わしい場合は、別のORDER BYを外側のSELECTに追加してください。 (この場合、内側のORDER BYは、この単純なクエリでは冗長なノイズになります。)

2