En langvarig diskussion i Oracles fora og nyhedsgrupper har været effektiviteten af at bruge count(*) til at returnere et rækkeantal fra en given tabel. En ny rynke i den diskussion introducerer nu count(rowid) som et mere effektivt alternativ; argumentet angiver, at count(*) udvider hele kolonnelisten, ligesom "vælg * ...", og som sådan kunne være en ressource-sink, når CLOB-kolonner er til stede i den ønskede tabel. Lad os se på det argument og se, om det holder vand. Lad os starte med at oprette og udfylde en tabel, der indeholder en CLOB-kolonne:
SQL>SQL> create table count_test( 2 id number, 3 val varchar2(40), 4 clb clob);Table created.SQL>SQL> start 2 for z in 1..1000000 loop 3 insert into count_test 4 værdier (z, 'Record '||z, 'Clob-værdi '||z); 5 endeløkke; 6 7 begå; 8 ende; 9 /PL/SQL-procedure gennemført.SQL>
Lad os derefter indstille begivenhed 10053 til at dumpe optimeringssporingen, så vi kan se, hvordan Oracle planlægger at udføre count()-forespørgslerne:
SQL> alter session set events ='10053 spor navn kontekst for evigt, niveau 2';Session ændret.
Scenen er sat, lad os køre nogle varianter af count() for at se, hvordan Oracle opfører sig. Først udfører vi en lige optælling(*) og viser planen:
SQL> vælg count(*) fra count_test; COUNT(*)---------- 1000000SQL> alter session set events ='10053 sporing navn kontekst fra';Session ændret.SQL> forklar plan for udvalgt count(*) fra count_test;Explained.SQL> vælg * fra tabel(dbms_xplan.display(null,null,'projektion'));PLAN_TABLE_OUTPUT-------------------------------------- -------------------------------------------------- --------------------------Plan hashværdi:371675025------------------------ --------------------+------------------------------------- ------+| Id | Betjening | Navn | Rækker | Bytes | Omkostninger | Tid |----------------------------------------+------ ----------------------------+| 0 | VÆLG UDTALELSE | | | | 3582 | || 1 | SORTERINGSSAMLÆG | | 1 | | | || 2 | TABELADGANG FULD | COUNT_TEST| 848K | | 3582 | 00:00:43 |----------------------------------------+--- ----------------------------------+ Kolonneprojektionsoplysninger (identificeret ved operations-id):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(*)[22] 2 - (rowset=1019)Bemærk----- - dynamisk statistik brugt:dynamisk sampling (niveau=2)19 rækker valgt.SQL>Når man ser på den genererede sporingsfil, bruger Oracle simpelthen count(*) som det er for at returnere resultaterne:
Endelig forespørgsel efter transformationer:******* UPARSET FORESPØRGSEL ER *******VÆLG ANTAL(*) "COUNT(*)" FRA "BING"."COUNT_TEST" "COUNT_TEST" ... ----- Forklar Plan Dump ---------- Plan Tabel -----=============Plan Tabel=============----------------------------------------+-------- --------------------------+| Id | Betjening | Navn | Rækker | Bytes | Omkostninger | Tid |----------------------------------------+------ ----------------------------+| 0 | VÆLG UDTALELSE | | | | 3582 | || 1 | SORTERINGSSAMLÆG | | 1 | | | || 2 | TABELADGANG FULD | COUNT_TEST| 848K | | 3582 | 00:00:43 |----------------------------------------+--- --------------------------------+ Forespørgselsbloknavn/objektalias (identificeret ved operations-id):---- -------------------------------------------------- ------1 - SEL$12 - SEL$1 / "COUNT_TEST"@"SEL$1"-------------------------------- -------------------------- Prædikatoplysninger:---------------------- ----------SQL>Ingen overraskelser der; Bemærk, at Oracle ikke udvider "*" til alle kolonner i tabellen - "*" i dette tilfælde angiver, at alle rækker skal tælles. Hvis et faktisk kolonnenavn var blevet angivet, ville Oracle have talt værdier i den angivne kolonne. Lad os nu se på, hvad Oracle gør med en count(rowid)-forespørgsel:
SQL> alter session set events ='10053 spor navn kontekst for evigt, niveau 2';Session ændret.SQL> vælg count(rowid) fra count_test;COUNT(ROWID)------------- 1000000SQL> alter session set events ='10053 spor navn kontekst fra';Session ændret.SQL> forklar plan for vælg count(rowid) fra count_test;Explained.SQL> vælg * fra tabel(dbms_xplan.display(null,null,'projektion) '));PLAN_TABLE_OUTPUT-------------------------------------------------- -------------------------------------------------- ----Planhashværdi:371675025------------------------------------------------+ -----------------------------------+| Id | Betjening | Navn | Rækker | Bytes | Omkostninger | Tid |----------------------------------------+------ ----------------------------+| 0 | VÆLG UDTALELSE | | | | 3582 | || 1 | SORTERINGSSAMLÆG | | 1 | 12 | | || 2 | TABELADGANG FULD | COUNT_TEST| 848K | 9941K | 3582 | 00:00:43 |----------------------------------------+--- ----------------------------------+ Kolonneprojektionsoplysninger (identificeret ved operations-id):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Bemærk----- - dynamisk statistik brugt:dynamisk sampling (niveau=2)19 rækker valgt.SQL>Oracle genererer en række værdier for hver række i tabellen, en operation som vil forbruge nogle CPU-ressourcer. Da forespørgslen vendte tilbage på nogenlunde samme tid som count(*)-versionen ser ydelsen "hit" ud til at være ubetydelig. Tilføjelse af en primær nøgle ændrer planerne en smule, men ikke forespørgselsteksten:
SQL> ændre tabel count_test add constraint count_pk primær nøgle(id); Tabel ændret. SQL>SQL> alter session set events ='10053 spor navn kontekst for evigt, niveau 2';Session ændret.SQL> vælg count(*) fra count_test; COUNT(*)---------- 1000000SQL> alter session set events ='10053 sporing navn kontekst fra';Session ændret.SQL> forklar plan for udvalgt count(*) fra count_test;Explained.SQL> vælg * fra tabel(dbms_xplan.display(null,null,'projektion'));PLAN_TABLE_OUTPUT-------------------------------------- -------------------------------------------------- ---------------------Plan hashværdi:371675025------------------------ -------------------------------------------------- | Id | Betjening | Navn | Rækker | Omkostninger (%CPU)| Tid |------------------------------------------------ --------------------------| 0 | VÆLG UDTALELSE | | 1 | 589 (2)| 00:00:01 || 1 | SORTERINGSSAMLÆG | | 1 | | || 2 | INDEKS HURTIG FULD SCAN| COUNT_PK | 848K| 589 (2)| 00:00:01 |------------------------------------------------ ------------------------------ Kolonneprojektionsoplysninger (identificeret ved operations-id):----------- -------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 2 - (rowset=1019)Bemærk----- - dynamisk statistik brugt:dynamisk sampling (level=2)19 rækker valgt.SQL>SQL>SQL> alter session sæt hændelser ='10053 spor navn kontekst for evigt, niveau 2'; Session ændret.SQL> vælg count(rowid) fra count_test;COUNT(ROWID)------ 1000000SQL> skift session sæt hændelser ='10053 spor navn kontekst fra';Session ændret.SQL> forklar plan for vælg count(rowid) fra count_test;Explained.SQL> vælg * fra tabel(dbms_xplan.display(null,null,'projection'));PLAN_TABLE_OUTPUT- -------------------------------------------------- ---------------------------------------Plan hashværdi:371675025------ -------------------------------------------------- --------------------------| Id | Betjening | Navn | Rækker | Bytes | Omkostninger (%CPU)| Tid |------------------------------------------------ ----------------------------------| 0 | VÆLG UDTALELSE | | 1 | 12 | 589 (2)| 00:00:01 || 1 | SORTERINGSSAMLÆG | | 1 | 12 | | || 2 | INDEKS HURTIG FULD SCAN| COUNT_PK | 848K| 9941K| 589 (2)| 00:00:01 |------------------------------------------------ -------------------------------------- Kolonneprojektionsoplysninger (identificeret ved operations-id):-- -------------------------------------------------- ------- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Bemærk----- - dynamisk statistik brugt:dynamisk sampling (niveau =2)19 rækker valgt.SQL>SQL> spool offcommit;10053-sporingsdetaljerne blev ikke ændret, efter at den primære nøgle blev tilføjet.
Det ser ud til, at der er hentet to stykker information fra dette eksperiment - count(rowid) er ikke bedre end count(*), når tabeller indeholder CLOB-kolonner, og at count(*) ikke udvider kolonnelisten, som "select *" gør (og der er ingen grund til at tro, at det skulle det).
Beviset er i buddingen, som det gamle ordsprog siger.
# # #
Se artikler afDavid Fitzjarrell