2013-02-19 223 views
5

我正在經歷SQLZOO 「SELECT within SELECT tutorial」,這裏是該做的工作(任務)這是一個緩慢的查詢嗎?可以改進嗎?

世界(名稱,大陸,面積,人口,國內生產總值)

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. 它可以重新編程沒有相關的子查詢嗎?
+0

下面是數據/查詢小提琴:http://sqlfiddle.com/#!4/2aed1/1 – Wilduck 2013-02-19 21:10:34

回答

1

如果你想重寫查詢沒有correalted子查詢,這裏是一個辦法:

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 ; 
+0

我喜歡你的解決方案(特別是第二個)。 我相信這是我正在尋找的。 – 2013-02-20 17:15:54

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比較運算符後跟一個子查詢成等價的條件,即使用任何比較運算符和互補的比較運算符

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比較運算符轉換條件的規則將第二個查詢轉換爲以下查詢,然後執行相關子查詢:

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 
       ); 

這我已經從Oracle源Link

採取了你的問題:

  1. 是oracle會照顧這作爲變換表明,甲骨文如何改變上述query.But更好地瞭解如何爲此結果查詢工作。
  2. 是的,這可以完成沒有相關的子查詢,但無論如何,你必須加入相同的表,因爲你需要比較表中有相同的大陸的其他記錄[請改正我,如果我錯了]
+0

我在想(也沒有找到),營造出一個解決方案「靜態'列表,通過評估每個大陸**符合標準的所有大陸**只有一次**。 – 2013-02-19 21:50:47

1

可以簡化這種無需掃描兩次表:

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;