5

私はSQLZOO「SELECTチュートリアル内のSELECT」を実行していましたが、これがその仕事をしたクエリの1つです(タスク7) 。

世界(名前、大陸、面積、人口、GDP)

SELECT w1.name, w1.continent, w1.population 
FROM world w1
WHERE 25000000 >= ALL(SELECT w2.population FROM world w2 WHERE w2.continent=w1.continent)

私の質問は、そのようなクエリの有効性についてです。サブクエリはメインクエリの各行(国)に対して実行されるため、特定の大陸のALLリストに繰り返し再入力されます。

  1. 私は心配する必要がありますか、それともOracle最適化が何らかの形でそれを処理しますか?
  2. 相関サブクエリなしで再プログラムできますか?
4

3 に答える 3

3

まず最初に、oracleがこのクエリをどのように変換して評価するかを理解する必要があります。

SELECT w1.name
     , w1.continent
     , w1.population 
FROM world w1
WHERE 25000000 >= ALL(SELECT w2.population 
                       FROM world w2 
                      WHERE w2.continent=w1.continent
                     );

これで、オプティマイザーは、ALL比較演算子とそれに続くサブクエリを使用する条件を、ANY比較演算子と補完的な比較演算子を使用する同等の条件に変換します。

  SELECT w1.name
        , w1.continent
       , w1.population 
  FROM world w1
   WHERE NOT(25000000 < ANY (SELECT w2.population 
                        FROM world w2 
                      WHERE w2.continent=w1.continent)
          );

次に、オプティマイザーは、ANY比較演算子を使用して条件を変換するためのルールを使用して、2番目のクエリを次のクエリにさらに変換し、その後に相関サブクエリを実行します。

  SELECT w1.name
       , w1.continent
       , w1.population 
   FROM world w1
  WHERE
     NOT EXISTS (SELECT w2.population 
                  FROM world w2 
                 WHERE w2.continent=w1.continent
                   AND 25000000 < w2.population
                );

これは私がオラクルのソースリンクから取ったものです

あなたの質問のために:

  1. はい、オラクルはこれを処理します。変換が示唆するように、オラクルは上記のクエリをどのように変換しますが、この最終結果のクエリがどのように機能するかをよりよく理解してください。
  2. はい、これは相関サブクエリなしで実行できますが、同じ大陸を持つテーブル内の他のレコードを比較する必要があるため、とにかく同じテーブルで結合する必要があります。[間違っている場合は修正してください]
于 2013-02-19T21:01:23.103 に答える
1

修正されたサブクエリなしでクエリを書き直したい場合は、次の1つの方法があります。

SELECT w1.name, w1.continent, w1.population 
FROM world w1
  JOIN
    ( SELECT continent, MAX(population) AS max_population
      FROM world
      GROUP BY continent
    ) c
    ON c.continent = w1.continent
WHERE 25000000 >= c.max_population ;

これが速くなることを意味するものではありません。Oracleのオプティマイザは非常に優れており、これは単純な全体的なクエリですが、どのように記述してもかまいません。別の簡略化は次のとおりです。

SELECT w1.name, w1.continent, w1.population 
FROM world w1
  JOIN
    ( SELECT continent
      FROM world
      GROUP BY continent
      HAVING MAX(population) <= 25000000 
    ) c
    ON c.continent = w1.continent ;
于 2013-02-20T08:23:57.767 に答える
1

テーブルを2回スキャンしなくても、これを簡略化できます。

select a.name, a.continent, a.population, a.max_pop
  from (select w1.name, w1.continent, w1.population, 
               max(w1.population) over (partition by w1.continent) max_pop
          from world w1
       ) a 
where 25000000 >= a.max_pop;
于 2013-02-20T08:16:23.017 に答える