Временните таблици на практика са същите като таблиците в паметта благодарение на кеширането и асинхронния I/O, а решението за временна таблица не изисква никакви допълнителни разходи за преобразуване между SQL и PL/SQL.
Потвърждаване на резултатите
Сравнявайки двете версии с RunStats, версията на временната таблица изглежда много по-зле. Всички тези боклуци за версията за временна таблица в Run1 и само малко допълнителна памет за версията PL/SQL в Run2. Отначало изглежда, че PL/SQL трябва да бъде ясният победител.
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
Но в края на деня само времето на стенния часовник има значение. И стъпките за зареждане и заявка се изпълняват много по-бързо с временни таблици.
Версията PL/SQL може да бъде подобрена чрез замяна на BULK COLLECT
с cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Но все още е значително по-бавна от версията за временна таблица.
Оптимизирано четене
Четенето от малката временна таблица използва само буферния кеш, който е в паметта. Изпълнете само частта със заявката много пъти и наблюдавайте как consistent gets from cache
(паметта) се увеличава, докато physical reads cache
(диск) остава същият.
select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Оптимизирани записи
В идеалния случай няма да има физически I/O, особено след като временната таблица е ON COMMIT DELETE ROWS
. И изглежда, че следващата версия на Oracle може да въведе такъв механизъм. Но това няма голямо значение в този случай, дисковият I/O изглежда не забавя нещата.
Изпълнете стъпката за зареждане няколко пъти и след това изпълнете select * from v$active_session_history order by sample_time desc;
. По-голямата част от I/O е BACKGROUND
, което означава, че нищо не го чака. Предполагам, че вътрешната логика на временната таблица е просто копие на обикновени DML механизми. По принцип нови данни в таблицата могат трябва да бъдат записани на диск, ако е ангажиран. Oracle може да започне да работи по него, например чрез преместване на данни от буфера на журнала на диск, но няма бързане, докато не се извърши действително COMMIT
.
Къде отива времето за PL/SQL?
Аз нямам представа. Има ли множество превключватели на контекста или едно преобразуване между SQL и PL/SQL двигателите? Доколкото знам нито един от наличните показатели не показва времето изразходвани за превключване между SQL и PL/SQL.
Може никога да не разберем точно защо PL/SQL кодът е по-бавен. Не се тревожа много за това. Общият отговор е, че по-голямата част от работата с базата данни трябва да се извършва в SQL така или иначе. Би имало много смисъл, ако Oracle отдели повече време за оптимизиране на ядрото на тяхната база данни, SQL, отколкото езика на добавките, PL/SQL.
Допълнителни бележки
За тестване на производителността може да бъде полезно да премахнете connect by
логиката в отделна стъпка. Този SQL е страхотен трик за зареждане на данни, но може да бъде много бавен и ресурсоемък. По-реалистично е да заредите примерна таблица веднъж с този трик и след това да вмъкнете от тази таблица.
Опитах да използвам новата функция на Oracle 12c, временно отмяна, и новата функция 18c, частни временни таблици. Нито едното не подобри производителността спрямо обикновените временни таблици.
Не бих заложил на това, но виждам начин резултатите да се променят напълно с увеличаването на данните. Буферът на журнала и кешът на буфера могат да станат толкова големи. И в крайна сметка този фонов вход/изход може да се добави и да затрупа някои процеси, превръщайки BACKGROUND
изчакайте в FOREGROUND
изчакайте. От друга страна, има само толкова много PGA памет за PL/SQL решението и тогава нещата се сриват.
И накрая, това отчасти потвърждава моя скептицизъм към „базите данни в паметта“. Кеширането не е нищо ново, базите данни го правят от десетилетия.