Tabele tymczasowe są w rzeczywistości takie same jak tabele w pamięci dzięki buforowaniu i asynchronicznym we/wy, a rozwiązanie w zakresie tabel tymczasowych nie wymaga żadnych dodatkowych nakładów na konwersję między SQL a PL/SQL.
Potwierdzanie wyników
Porównując obie wersje z RunStats, tymczasowa wersja tabeli wygląda duzo gorszy. Wszystkie te śmieci dla wersji tabeli tymczasowej w Run1 i tylko trochę dodatkowej pamięci dla wersji PL/SQL w Run2. Na początku wydaje się, że PL/SQL powinien być wyraźnym zwycięzcą.
Type Name Run1 (temp) Run2 (PLSQL) Diff
----- -------------------------------- ------------ ------------ ------------
...
STAT physical read bytes 81,920 0 -81,920
STAT physical read total bytes 81,920 0 -81,920
LATCH cache buffers chains 104,663 462 -104,201
STAT session uga memory 445,488 681,016 235,528
STAT KTFB alloc space (block) 2,097,152 0 -2,097,152
STAT undo change vector size 2,350,188 0 -2,350,188
STAT redo size 2,804,516 0 -2,804,516
STAT temp space allocated (bytes) 12,582,912 0 -12,582,912
STAT table scan rows gotten 15,499,845 0 -15,499,845
STAT session pga memory 196,608 19,857,408 19,660,800
STAT logical read bytes from cache 299,958,272 0 -299,958,272
Ale pod koniec dnia liczy się tylko czas zegara ściennego. Zarówno ładowanie, jak i wykonywanie zapytań przebiegają znacznie szybciej w przypadku tabel tymczasowych.
Wersję PL/SQL można ulepszyć, zastępując BULK COLLECT
z cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Ale nadal jest znacznie wolniejszy niż wersja tymczasowej tabeli.
Zoptymalizowane odczyty
Odczyt z małej tabeli tymczasowej wykorzystuje jedynie bufor bufora, który znajduje się w pamięci. Uruchom tylko część zapytania wiele razy i obserwuj, jak consistent gets from cache
(pamięć) wzrasta, gdy physical reads cache
(dysk) pozostanie taki sam.
select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Zoptymalizowane zapisy
Idealnie byłoby, gdyby nie było fizycznych operacji we/wy, zwłaszcza, że tabela tymczasowa to ON COMMIT DELETE ROWS
. I wygląda na to, że kolejna wersja Oracle może wprowadzić taki mechanizm. Ale w tym przypadku nie ma to większego znaczenia, dyskowe I/O nie wydaje się spowalniać.
Uruchom krok ładowania wiele razy, a następnie uruchom select * from v$active_session_history order by sample_time desc;
. Większość I/O to BACKGROUND
, co oznacza, że nic na nią nie czeka. Zakładam, że wewnętrzna logika tabeli tymczasowej jest po prostu kopią zwykłych mechanizmów DML. Ogólnie rzecz biorąc, nowe dane tabeli mogą musi być zapisany na dysku, jeśli jest popełniony. Oracle może zacząć nad tym pracować, na przykład przenosząc dane z bufora dziennika na dysk, ale nie ma pośpiechu, dopóki nie nastąpi faktyczne COMMIT
.
Gdzie idzie czas PL/SQL?
Nie mam pojęcia. Czy istnieje wiele przełączników kontekstu lub pojedyncza konwersja między silnikami SQL i PL/SQL? O ile wiem, żaden z dostępnych wskaźników nie pokazuje czasu spędziłem na przełączaniu się między SQL a PL/SQL.
Możemy nigdy nie wiedzieć dokładnie, dlaczego kod PL/SQL jest wolniejszy. Nie przejmuję się tym zbytnio. Ogólna odpowiedź brzmi:zdecydowana większość pracy z bazą danych i tak musi być wykonana w SQL. Byłoby dużo sensu, gdyby Oracle poświęciło więcej czasu na optymalizację rdzenia swojej bazy danych, SQL, niż języka dodatkowego, PL/SQL.
Dodatkowe uwagi
W przypadku testowania wydajności pomocne może być usunięcie connect by
logiki w oddzielnym kroku. Ten kod SQL to świetna sztuczka do ładowania danych, ale może być bardzo powolna i wymagająca dużej ilości zasobów. Bardziej realistycznie jest załadować przykładową tabelę raz za pomocą tej sztuczki, a następnie wstawić ją z tej tabeli.
Próbowałem użyć nowej funkcji Oracle 12c, tymczasowego cofania i nowej funkcji 18c, prywatnych tabel tymczasowych. Żaden z nich nie poprawił wydajności w porównaniu ze zwykłymi tabelami tymczasowymi.
Nie stawiałbym na to, ale widzę sposób, w jaki wyniki zmienią się całkowicie, gdy dane będą większe. Bufor dziennika i pamięć podręczna bufora mogą być tylko tak duże. I w końcu to we/wy w tle może sumować się i przytłaczać niektóre procesy, zmieniając BACKGROUND
czekać na FOREGROUND
czekać. Z drugiej strony jest tylko tyle pamięci PGA dla rozwiązania PL/SQL, a potem wszystko się zawiesza.
W końcu to częściowo potwierdza mój sceptycyzm wobec "baz danych w pamięci". Buforowanie nie jest niczym nowym, bazy danych robią to od dziesięcioleci.