Dlouhotrvající diskuse na fórech a diskusních skupinách Oracle se týkala efektivity použití count(*) k vrácení počtu řádků z dané tabulky. Nová vráska v této diskusi nyní představuje count(rowid) jako účinnější alternativu; argument uvádí, že count(*) rozšiřuje celý seznam sloupců, podobně jako „select * …“, a jako takový by mohl být jímkou zdrojů, pokud jsou v požadované tabulce přítomny sloupce CLOB. Podívejme se na tento argument a uvidíme, zda obstojí. Začněme vytvořením a naplněním tabulky obsahující sloupec CLOB:
SQL>SQL> vytvořit tabulku count_test( 2 id number, 3 val varchar2(40), 4 clb clob);Table created.SQL>SQL> begin 2 for z v 1..1000000 loop 3 insert into count_test 4 values (z, 'Záznam '||z, 'Hodnota Clobu '||z); 5 koncová smyčka; 6 7 zavázat se; 8 konec; 9 /PL/SQL procedura úspěšně dokončena.SQL>
Dále nastavíme událost 10053, aby vypsala trasování optimalizátoru, abychom viděli, jak Oracle plánuje provést dotazy count():
SQL> alter session set events ='10053 kontext názvu trasování navždy, úroveň 2';Relace změněna.
Fáze je připravena, spustíme několik variant count(), abychom viděli, jak se Oracle chová. Nejprve provedeme rovný počet (*) a zobrazíme plán:
SQL> select count(*) from count_test; COUNT(*)---------- 1000000SQL> alter session set events ='10053 kontext názvu trasování vypnut';Session altered.SQL> vysvětlit plán výběru count(*) z testu count;Explained.SQL> select * z tabulky(dbms_xplan.display(null,null,'projekce'));PLAN_TABLE_OUTPUT------------------------------- -------------------------------------------------- -------------------------Hodnota hash plánu:371675025--------------------- --------------------+----------------------------- ------+| Id | Provoz | Jméno | Řádky | Bajty | Cena | Čas |----------------------------------------+------- ----------------------------+| 0 | VYBERTE PROHLÁŠENÍ | | | | 3582 | || 1 | SEŘADIT SOUHRN | | 1 | | | || 2 | PŘÍSTUP K TABULCE PLNÝ | COUNT_TEST| 848 tis. | | 3582 | 00:00:43 |----------------------------------------+--- --------------------------------+ Informace o projekci sloupců (identifikováno podle ID operace):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(*)[22] 2 - (rowset=1019)Poznámka----- - použitá dynamická statistika:dynamické vzorkování (level=2)19 vybraných řádků.SQL>Při pohledu na vygenerovaný trasovací soubor Oracle jednoduše použije count(*) tak, jak je, aby vrátil výsledky:
Konečný dotaz po transformacích:******* NEPARSOVANÝ DOTAZ JE *******SELECT COUNT(*) "COUNT(*)" Z "BING"."COUNT_TEST" "COUNT_TEST" ... ----- Vysvětlení výpisu plánu ---------- Tabulka plánu -----============Tabulka plánu============----------------------------------------+--------- ---------------------------+| Id | Provoz | Jméno | Řádky | Bajty | Cena | Čas |----------------------------------------+------- ----------------------------+| 0 | VYBERTE PROHLÁŠENÍ | | | | 3582 | || 1 | SEŘADIT SOUHRN | | 1 | | | || 2 | PŘÍSTUP K TABULCE PLNÝ | COUNT_TEST| 848 tis. | | 3582 | 00:00:43 |----------------------------------------+--- -------------------------------+ Název bloku dotazu / Alias objektu (identifikováno pomocí ID operace):---- -------------------------------------------------- ------1 – 12 SEL – 1 SEL / "COUNT_TEST"@"SEL $1"---------------------------- --------------------------------Informace o predikátu:---------------- ---------SQL>Žádné překvapení; všimněte si, že Oracle nerozšiřuje „*“ na všechny sloupce v tabulce – „*“ v tomto případě znamená, že se mají počítat všechny řádky. Pokud by byl poskytnut skutečný název sloupce, Oracle by započítal hodnoty v uvedeném sloupci. Podívejme se nyní na to, co Oracle dělá s count(rowid) dotazem:
SQL> alter session set events ='10053 kontext názvu trasování navždy, úroveň 2';Session altered.SQL> select count(rowid) from count_test;COUNT(ROWID)------------- 1000000SQL> alter session set events ='10053 kontext názvu trasování vypnut';Session altered.SQL> vysvětlit plán pro select count(rowid) z count_test;Explained.SQL> select * from table(dbms_xplan.display(null,null,'projection '));PLAN_TABLE_OUTPUT--------------------------------------------- -------------------------------------------------- ----Hodnota hash plánu:371675025----------------------------------------+ -----------------------------------+| Id | Provoz | Jméno | Řádky | Bajty | Cena | Čas |----------------------------------------+------- ----------------------------+| 0 | VYBERTE PROHLÁŠENÍ | | | | 3582 | || 1 | SEŘADIT SOUHRN | | 1 | 12 | | || 2 | PŘÍSTUP K TABULCE PLNÝ | COUNT_TEST| 848 tis. | 9941K | 3582 | 00:00:43 |----------------------------------------+--- --------------------------------+ Informace o projekci sloupců (identifikováno podle ID operace):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Poznámka----- - použitá dynamická statistika:dynamické vzorkování (úroveň=2)19 řádků selected.SQL>Oracle generuje hodnotu rowid pro každý řádek v tabulce, což je operace, která spotřebuje určité prostředky CPU. Vzhledem k tomu, že se dotaz vrátil zhruba ve stejnou dobu jako verze count(*), zdá se, že výkonový „hit“ je zanedbatelný. Přidání primárního klíče mírně změní plány, ale ne text dotazu:
SQL> alter table count_test přidat omezení count_pk primární klíč(id);Tabulka změněna. SQL>SQL> alter session set events ='10053 trasování kontextu názvu navždy, úroveň 2';Relace změněná.SQL> select count(*) from count_test; COUNT(*)---------- 1000000SQL> alter session set events ='10053 kontext názvu trasování vypnut';Session altered.SQL> vysvětlit plán výběru count(*) z testu count;Explained.SQL> select * z tabulky(dbms_xplan.display(null,null,'projekce'));PLAN_TABLE_OUTPUT------------------------------- -------------------------------------------------- ---------------------Hodnota hash plánu:371675025------------------------- -------------------------------------------------- | Id | Provoz | Jméno | Řádky | Cena (%CPU)| Čas |------------------------------------------------ ---------------------------| 0 | VYBERTE PROHLÁŠENÍ | | 1 | 589 (2)| 00:00:01 || 1 | SEŘADIT SOUHRN | | 1 | | || 2 | INDEX RYCHLÉ ÚPLNÉ SKENOVÁNÍ| COUNT_PK | 848 tis.| 589 (2)| 00:00:01 |-------------------------------------------- ------------------------------ Informace o projekci sloupců (identifikováno podle ID operace):---------- ------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 2 - (sada řádků=1019)Poznámka----- - použitá dynamická statistika:dynamické vzorkování (level=2)19 vybraných řádků.SQL>SQL>SQL> alter události sady relací ='10053 kontext názvu trasování navždy, úroveň 2';Změněna relace.SQL> select count(rowid) from count_test;COUNT(ROWID)------------ 1000000SQL> změna událostí sady session ='10053 kontext názvu trasování vypnut';Session altered.SQL> vysvětlit plán pro select count(rowid) z count_test;Explained.SQL> select * from table(dbms_xplan.display(null,null,'projection'));PLAN_TABLE_OUTPUT- -------------------------------------------------- ---------------------------------------Hodnota hash plánu:371675025------ -------------------------------------------------- ---------------------------| Id | Provoz | Jméno | Řádky | Bajty | Cena (%CPU)| Čas |------------------------------------------------ ----------------------------------| 0 | VYBERTE PROHLÁŠENÍ | | 1 | 12 | 589 (2)| 00:00:01 || 1 | SEŘADIT SOUHRN | | 1 | 12 | | || 2 | INDEX RYCHLÉ ÚPLNÉ SKENOVÁNÍ| COUNT_PK | 848 tis.| 9941K| 589 (2)| 00:00:01 |-------------------------------------------- -------------------------------------- Informace o projekci sloupců (identifikováno podle ID operace):-- -------------------------------------------------- ------- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (sada řádků=256) ROWID[ROWID,10]Poznámka----- - použitá dynamická statistika:dynamické vzorkování (úroveň =2) 19 vybraných řádků.SQL>SQL> zařazování offcommit;Podrobnosti trasování 10053 se po přidání primárního klíče nezměnily.
Zdá se, že z tohoto experimentu byly získány dvě informace – count(rowid) není o nic lepší než count(*), když tabulky obsahují sloupce CLOB a tento count(*) nerozšiřuje seznam sloupců, jako to dělá „select *“. (a není důvod se domnívat, že by mělo).
Důkazem je pudink, jak říká staré přísloví.
# # #
Viz články odDavida Fitzjarrella