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


12

ルーカスエダーとのTwitter会話でこの質問に遭遇しました。

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

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

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

したがって、プランナーは最も外側のクエリを冗長にするか、単に内部のテーブルからの結果を通過させるため、単純にそのクエリを破棄すると想定します。

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


4
SQL Serverではクエリが失敗することに注意してください。これは、派生テーブル内ではorder byが許可されていないためです。
a_horse_with_no_name 2017

なぜあなたはそんなに信じられないのですか?なぜあなたは何かを仮定しますか?あなたに選択肢を与えるプログラムを書くとき、あなたはユーザーがあなたの選択について期待することを期待しますか?論理および物理クエリの最適化/実装について読んでください。
philipxy 2017

2
「プランナーは、最も外側のクエリが冗長であるか、単に内部のテーブルからの結果を通過するため、単純にそれを破棄すると思います。」 あなたは同じように簡単にプランナーが破棄されると仮定可能性が発注句をインナーそれは文脈で無意味だからクエリ。
ワイルドカード

MariaDBは2012年頃にこの問題について議論しています。groupwise maxのORDER BY異なる最適化への内部リードの欠如。
リック・ジェームス

1
実際、あなたはPostgresに適しています。
Erwin Brandstetter 2017

回答:


20

ほとんどのデータベースは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

この特定のケースでは、派生テーブルの順序を最も外側のSELECTで明示的に再利用できます。

Oracleに関する注意事項:

Oracle では、をOFFSET使用してページ分割を実装することが長年行われてきましたROWNUM。これは、派生テーブルを注文した後にのみ合理的に計算できます。

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

Meaningless: E.g. PostgreSQLそれ何かを意味するので、「信頼できない」のはずです。行は内部クエリで並べ替えられ、その順序は、特に指示がない限り、または追加の操作で並べ替えが適切な場合を除き、外部クエリレベルで保持されます。それが単なる実装の詳細であっても、意味がありません。これは、集計関数へのソートされた入力に使用できます。マニュアルはさらに多くのことを示唆しています: Alternatively, supplying the input values from a sorted subquery will usually work.
Erwin Brandstetter

Postgresに追加した引用は、実際には別のケースに適用さORDER BYれます。まったくないクエリです。
Erwin Brandstetter 2017

@ErwinBrandstetter:これらの詳細を含む回答を自由に追加してください。個人的には、実装の詳細に意味があるとは思いません。ちょうど今日、私は昔、OracleがOracle 8iでのソートされたグループごとの操作の実行に常に依存していたことを知っていました(私は信じます)、突然、新しいバージョンがハッシュグループを導入しました。注文は信頼できます。言い換えれば、私はそれを大胆な言葉で表現するのが好きです。意味がありません。バージョンxyzの複雑な詳細を知っていれば、実際にはできます...
Lukas Eder

すでに回答を追加しました。非標準の動作を無視することを選択したのか、それとも他にどのような良いアドバイスがあるのか、質問の横にあります。指定されたクエリの順序は保証されますか?Postgres用です。他のRDBMSには適用されません(または適用されません)。これは、バージョンxyzだけでなく、既存のすべてのバージョンのPostgresに適用されます。あなたの引用は誤解を招くものです。非標準の動作を無視したい場合は、Oracleから始めて、NULLと空の文字列は同じであると信じ込ませます。また、質問に直交しています。
Erwin Brandstetter 2017

@ErwinBrandstetter:興味深い、更新ありがとうございます。文書化されていることを保証しますか?
Lukas Eder

12

はい。なければORDER BY句の出力順序が定義されていないと、クエリプランナは、あなたがこのことを知っていると理解していることを前提とするだけでなく、その範囲内です。

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

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


PostgreSQLでテストすると、ORDER BYで使用される列にインデックスがなかったため、順次スキャン後にソートが行われました。内部クエリORDER BYをスキップすると思うRDBMSはどれですか。
Vlad Mihalcea 2017

5
私が何をするかわからないと言うことはできません。彼らが望むなら、彼らは誰でも完全に自由にすることができます。それは、一般的な規格と製品仕様の両方による完全に許容できる最適化です。SQL Serverはクエリを完全に拒否します(含めない限りTOP 100%、現在のクエリは移植可能ではありません。それがプロジェクトの優先順位である必要があります。Postgresは内部クエリの順序に従っているため、将来も常に実行されるとは限りません(または実際には古いバージョンがそうするので)
念の

1
@VladMihalcea冗長性を「最適化」するDBMS ORDER BYMariaDB
ypercubeᵀᴹ

6

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

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


2
順序を最適化する理由の1つは速度です。行を別の順序で返す方が効率的です。
TomTom 2017

2
特に、サーバーは並列処理を利用してテーブルを読み取る場合があります。そうする場合、順序を強制する必要がない場合は、スレッドがそれらを読み取っても、行が返されます。(SQL Serverが実際にように、これを実行しSELECTていないとORDER BY。本当にだけで理論的には、データが変更されたため、非決定的ではなく、)
のJeroen Mostert

@JeroenMostert:未定義の動作は悪化するだけです。順不同で、配列にインデックスを付けるためにデルタが使用された場合はどうなりますか?
ジョシュア

2

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

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

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

マニュアルでは、「集計関数」の章にも多くのことを示しています。

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

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


"table"単純なベーステーブルではなく、複雑なビューまたはパーティションテーブルである場合、それは本当ですか?プランにも並列実行がある場合は本当ですか?Postgres 10でも同じですか?(私は質問しているだけで、これらの質問のいずれの答えかは
わかりませ

@ypercubeᵀᴹ:私はこれらすべてについてPostgres 10をテストしていませんが、いずれにしてもそれが真実であると確信しています。単純なケースの外部クエリでは、順序が適用され、変更されません。
Erwin Brandstetter 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.