2

いくつかのテーブルからランダムなサンプルを取得していますが、クエリの書き方によっては機能しないことに気付きました。明らかに、私は all_tab_columns を使用していませんでした。バニラ インスタンス (9.2.0.8) で動作する例を提供しただけです。

なぜこれが機能するのですか?

select * from (
    select 
        floor(dbms_random.value(0,1000)) as randomval
    from 
        all_tab_columns where rownum < 10000
) where randomval > 200 and randomval < 300;

しかし、これは結果を返しません。

select * from (
    select 
        floor(dbms_random.value(0,1000)) as randomval
    from 
        all_tab_columns 
) where randomval > 200 and randomval < 300;

クエリの rownum < 10000 は何を達成しますか?

編集:何が機能しないかを明確にしました。

編集:バージョン9.2.0.8を追加

4

3 に答える 3

2

明確な答えはありませんが、理論はあります...

私の推測では、2番目のクエリはこれに最適化されています。

select * 
  from all_tab_columns 
 where floor(dbms_random.value(0,1000))> 200 
   and floor(dbms_random.value(0,1000)) < 300;

どういうわけかrownum、インラインビューに基準があると、その最適化が妨げられます。

これはまた、私たちの一部(私を含む)があなたが説明した問題を見ることができない理由を説明するかもしれません-私たちは異なるバージョンのOracleを使用しており、クエリは私たちのために異なる方法で最適化されます。

編集

少しグーグルした後、私はこのAskTomの質問に出くわしました。これは関連しているようです。トム・カイトの答えは次の行で終わります。

SQLから関数を呼び出すときは、関数が呼び出される頻度、順序などに依存しない方がよいでしょう。要するに、何も仮定しないでください。そして覚えておいてください-SQLの書き換えが始まり、私たちは常にSQLを書き換えます。副作用に頼らないでください

于 2013-02-26T21:52:31.000 に答える
1

@Peter は何かに取り組んでいると思いますが、もう少し説明が必要です。

Oracle では、関数は DETERMINISTIC であってもなくてもかまいません。これは、関数が同じ引数で呼び出された場合、同じ値を返すことを意味します。したがって、sqrt()決定論的です。dbms_random()ではありません。他のデータベースでは、2 つのカテゴリに対して STABLE と VOLATILE という用語を使用しています。

推測するに、Oracle エンジンは、次のクエリが行を返す必要があることを認識できるほどスマートです。

select * from (
    select 
        dbms_random.value(0,1000) as randomval
    from 
        all_tab_columns 
) where randomval > 200 and randomval < 300;

しかし、私はそれが原因でつまずいていると思いfloor()ます。つまり、コンパイラは「安定した」関数を検出するため、以前の値を検索するだけです。そして、キャッシュされた値を使用して、関数を複数回呼び出してショートサーキットします。

これが正しければ、上記のクエリは行を返します。もしそうなら、私はこのデータベースの「機能」をバグと呼んでいます。おそらくどこかにデータベース最適化エンジニアがいて、これを非常に便利な機能として擁護しているでしょう。

于 2013-02-26T22:27:04.853 に答える
0

どちらのクエリも Oracle 11g R2 で機能します。ROWNUM は Oracle の疑似列です。興味があればそれについて読むことができます。

于 2013-02-27T20:49:13.080 に答える