Czas rozprawić się ze zbyt często powtarzaną herezją, zanim stanie się prawdą…
Elementem techniki kosztowej optymalizacji zapytań jest szacowanie kosztów alternatywnych planów wykonania zapytania. Odbywa się ono automatycznie podczas przetwarzania polecenia SQL przez optymalizator zapytań. Plan wykonania, którego szacowany koszt okazał się najniższy ze wszystkich rozważanych, jest wybierany jako plan do realizacji. Programista ma możliwość obejrzenia zarysu najlepszego (najtańszego) planu wykonania zapytania (np. poleceniem EXPLAIN PLAN FOR lub – lepiej – zapytaniem do funkcji pakietu DBMS_XPLAN). Wraz ze strukturą planu wykonania prezentowana jest właśnie zwycięska wartość kosztu tego planu. I tu zaczynają się problemy…
Funkcjonuje dość powszechne, błędne przekonanie, że wyświetlany koszt planu wykonania zapytania należy traktować jako reprezentację szacowanego czasu jego wykonania. Czyli, że wyższy koszt = dłuższy czas, niższy koszt = krótszy czas, dwukrotnie wyższy koszt = dwukrotnie wyższy czas, itp. Niestety, tak można było rozumieć koszt wiele lat temu, kiedy Oracle sam interpretował jednostkę kosztu jako czas pojedynczej operacji dyskowego wejścia-wyjścia. Obecnie formuły szacowania kosztu są tak bardzo „skażone” różnymi korektami, wagami, preferencjami, itp., że należy całkowicie odstąpić od pomysłu zestawiania kosztów dla DWÓCH RÓŻNYCH ZAPYTAŃ i wyciągania z tego jakichkolwiek wniosków. Koszt ma sens wyłącznie podczas porównywania alternatywnych planów TEGO SAMEGO zapytania – to właśnie robi optymalizator kosztowy podczas pracy. Jeśli zależy nam na porównaniu czasów wykonania dwóch zapytań, to je po prostu wykonajmy i zmierzmy czas (lub przeanalizujmy statystyki wykonania).
Zwróćmy uwagę na poniższy przykład dwóch prostych zapytań pobierających wszystkie rekordy z tej samej tabeli. Pierwsze zapytanie posługuje się hintem wymuszającym wykonanie sekwencyjne, drugie zapytanie wymusza zrównoleglenie wykonania w stopniu 200. Przyjrzyjmy się czasowi wykonania pierwszego zapytania – 40 sekund, drugiego – 42 sekundy. A koszty? Proszę bardzo – szybsze zapytanie (sekwencyjne) prezentuje koszt 1231, a drugie, wolniejsze zapytanie (zrównoleglone) – koszt 7!!! Pewnie programista widząc koszt 7 ucieszy się z ogromnej poprawy wydajności…
SQL> select /*+ NO_PARALLEL */ * from sales_t;
10107273 rows selected.
Elapsed: 00:00:40.68
Execution Plan
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 918K| 25M| 1231 (1)| 00:00:01 |
| 1 | TABLE ACCESS FULL| SALES_T | 918K| 25M| 1231 (1)| 00:00:01 |
-----------------------------------------------------------------------------
SQL> select /*+ PARALLEL(200) */ * from sales_t
10107273 rows selected.
Elapsed: 00:00:42.73
Execution Plan
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 918K| 25M| 7 (0)| 00:00:01|
| 1 | PX COORDINATOR | | | | | |
| 2 | PX SEND QC (RANDOM)| :TQ10000 | 918K| 25M| 7 (0)| 00:00:01|
| 3 | PX BLOCK ITERATOR | | 918K| 25M| 7 (0)| 00:00:01|
| 4 | TABLE ACCESS FULL| SALES_T | 918K| 25M| 7 (0)| 00:00:01|
--------------------------------------------------------------------------------
Kwestię posługiwania się kosztem planu wykonania zapytania znakomicie skomentował kiedyś Tom Kyte:
I don't know how to say it
I'll shout
THE COST HAS NOTHING WHATSOEVER TO DO WITH THE RUNTIME PERFORMANCE OF A QUERY.
YOU CANNOT COMPARE THEM AND SAY "THIS WILL BE FASTER"
IT IS NOT A BUG, IT IS A DESIGN FEATURE, THE WAY IT WORKS. IT IS DOING THIS ON PURPOSE.