2013-02-19 13 views
5

szedłem SQLZOO "SELECT within SELECT tutorial", a oto jeden z zapytaniami, że spełnił swoje zadanie (zadanie)Czy to powolne zapytanie? Czy można to poprawić?

świecie (nazwa, kontynent, obszaru, ludności, PKB)

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

Moje pytania dotyczą skuteczności takiego zapytania. Zapytanie podrzędne będzie uruchamiane dla każdego wiersza (kraju) głównego zapytania, a tym samym wielokrotnie ponownie wypełnia listę ALL dla danego kontynentu.

  1. Czy powinienem się martwić, czy optymalizacja Oracle w jakiś sposób się tym zajmie?
  2. Czy można go przeprogramować bez skorelowanej pod-zapytania?
+0

Oto skrzypce dla danych/zapytania: http://sqlfiddle.com/#!4/2aed1/1 – Wilduck

Odpowiedz

1

Jeśli chcą przepisać zapytanie bez correalted podzapytania, tutaj jest jeden sposób:

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 ; 

Nie sugeruję, że będzie to szybsze. Optymalizator Oracle jest całkiem niezły i jest to prosta ogólna kwerenda, jednak ją piszesz. Oto kolejny uproszczenie:

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

Podoba mi się Twoje rozwiązanie (szczególnie drugie). Wierzę, że tego właśnie szukałem. –

3

Przede wszystkim musisz zrozumieć, jak wyrocznia przekształcić to zapytanie do oceny.

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

teraz optymalizator zmienia stan, który zastosowano operator porównania Wszystkie następnie podkwerendzie w równoważnym warunkiem, że używa każdy operator porównania i komplementarną operator porównania

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

optymalizator następnie dalsze transformat drugie zapytanie do następującego zapytania przy użyciu reguły do ​​transformowania warunków za pomocą operatora ANY porównania, a następnie skorelowane podzapytanie:

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

to wziąłem od źródła oracle Link

na Wasze pytania:

  1. Tak oracle zadba o to, jak transformacja sugerują, jak wyrocznia przekształcić powyższe query.But lepiej zrozumieć, jak to się skończy praca z zapytaniem o wyniki.
  2. tak, można to zrobić bez skorelowanej sub zapytania, ale w każdym razie musisz przyłączyć się do tej samej tabeli, ponieważ musisz porównać inne rekordy w tabeli, która ma ten sam kontynent. [Proszę, popraw mnie, jeśli się mylę]
+0

myślałem (ale nie mógł znaleźć) rozwiązanie, które buduje " statyczna "lista wszystkich kontynentów, które pasują do kryterium, oceniając każdy kontynent ** tylko raz". –

1

można uprościć ten bez konieczności analizowania tabeli dwukrotnie:

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;