sql >> Databasteknik >  >> RDS >> Oracle

Är COUNT(rovid) snabbare än COUNT(*)?

En långvarig diskussion i Oracle-forum och nyhetsgrupper har varit effektiviteten i att använda count(*) för att returnera ett radantal från en given tabell. En ny rynka i den diskussionen introducerar nu count(rowid) som ett mer effektivt alternativ; argumentet säger att count(*) expanderar hela kolumnlistan, ungefär som "select * ...", och som sådan kan det vara en resurssink när CLOB-kolumner finns i den önskade tabellen. Låt oss titta på det argumentet och se om det håller vatten. Låt oss börja med att skapa och fylla i en tabell som innehåller en CLOB-kolumn:

SQL>SQL> skapa tabell count_test( 2 id nummer, 3 val varchar2(40), 4 clb clob); Tabell skapad.SQL>SQL> börjar 2 för z i 1..1000000 loop 3 infoga i count_test 4 värden (z, 'Record'||z, 'Clob-värde'||z); 5 ändögla; 6 7 begå; 8 ände; 9 /PL/SQL-proceduren slutförd.SQL>

Låt oss sedan ställa in händelse 10053 för att dumpa optimeringsspåret så att vi kan se hur Oracle planerar att köra count()-frågorna:

SQL> alter session set events ='10053 spåra namnkontext för alltid, nivå 2';Session ändrad.

Scenen är klar, låt oss köra några varianter av count() för att se hur Oracle beter sig. Först kör vi en rak räkning(*) och visar planen:

SQL> välj count(*) från count_test; COUNT(*)---------- 1000000SQL> ändra sessionsuppsättningshändelser ='10053 spåra namnkontext av';Sessionen ändrad.SQL> förklara plan för valt antal(*) från count_test;Explained.SQL> välj * från tabell(dbms_xplan.display(null,null,'projektion'));PLAN_TABLE_OUTPUT-------------------------------------- -------------------------------------------------- --------------------------Planhashvärde:371675025------------------------- --------------------+------------------------------------- ------+| Id | Operation | Namn | Rader | Bytes | Kostnad | Tid |----------------------------------------+------- ----------------------------+| 0 | VÄLJ UTTALANDE | | | | 3582 | || 1 | SORTERA AGGREGATER | | 1 | | | || 2 | BORDTILLGÅNG FULLSTÄNDIG | COUNT_TEST| 848K | | 3582 | 00:00:43 |----------------------------------------+--- ----------------------------------+ Kolumnprojektionsinformation (identifierad med operations-id):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(*)[22] 2 - (rowset=1019)Obs----- - dynamisk statistik använd:dynamisk sampling (nivå=2)19 rader valda.SQL> 

När du tittar på spårningsfilen som genereras använder Oracle helt enkelt count(*) som det är för att returnera resultaten:

Slutlig fråga efter transformationer:******* OPARSED FRÅGA ÄR *******VÄLJ ANTAL(*) "COUNT(*)" FRÅN "BING"."COUNT_TEST" "COUNT_TEST" ... ----- Förklara plandump ---------- Plantabell -----=============Plantabell=============----------------------------------------+-------- --------------------------+| Id | Operation | Namn | Rader | Bytes | Kostnad | Tid |----------------------------------------+------- ----------------------------+| 0 | VÄLJ UTTALANDE | | | | 3582 | || 1 | SORTERA AGGREGATER | | 1 | | | || 2 | BORDTILLGÅNG FULLSTÄNDIG | COUNT_TEST| 848K | | 3582 | 00:00:43 |----------------------------------------+--- --------------------------------+ Frågeblocknamn/objektalias (identifierad av operations-id):---- -------------------------------------------------- ------1 - SEL$12 - SEL$1 / "COUNT_TEST"@"SEL$1"---------------------------------- --------------------------Predikatinformation:--------------------- ----------SQL>

Inga överraskningar där; Observera att Oracle inte expanderar "*" till alla kolumner i tabellen - "*" i detta fall indikerar att alla rader ska räknas. Hade ett faktiskt kolumnnamn angetts skulle Oracle ha räknat värden i den angivna kolumnen. Låt oss nu titta på vad Oracle gör med en count(rowid)-fråga:

SQL> alter session set events ='10053 spåra namnkontext för alltid, nivå 2';Session altered.SQL> välj count(rowid) från count_test;COUNT(ROWID)------- 1000000SQL> alter session set events ='10053 spåra namnkontext av';Session ändrad.SQL> förklara plan för välj count(rovid) från count_test;Explained.SQL> välj * från tabellen(dbms_xplan.display(null,null,'projection) '));PLAN_TABLE_OUTPUT-------------------------------------------------- -------------------------------------------------- ----Planhashvärde:371675025------------------------------------------------+ ----------------------------------+| Id | Operation | Namn | Rader | Bytes | Kostnad | Tid |----------------------------------------+------- ----------------------------+| 0 | VÄLJ UTTALANDE | | | | 3582 | || 1 | SORTERA AGGREGATER | | 1 | 12 | | || 2 | BORDTILLGÅNG FULLSTÄNDIG | COUNT_TEST| 848K | 9941K | 3582 | 00:00:43 |----------------------------------------+--- ----------------------------------+ Kolumnprojektionsinformation (identifierad med operations-id):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Obs----- - dynamisk statistik använd:dynamisk sampling (nivå=2)19 rader vald.SQL>

Oracle genererar ett radvärde för varje rad i tabellen, en operation som kommer att förbruka en del CPU-resurser. Eftersom frågan returnerades på ungefär samma tid som count(*)-versionen verkar prestandan "träffen" vara försumbar. Att lägga till en primärnyckel ändrar planerna något men inte frågetexten:

SQL> ändra tabell count_test add constraint count_pk primärnyckel(id); Tabell ändrad. SQL>SQL> alter session set events ='10053 spåra namnkontext för alltid, nivå 2';Session ändrad.SQL> välj count(*) från count_test; COUNT(*)---------- 1000000SQL> ändra sessionsuppsättningshändelser ='10053 spåra namnkontext av';Sessionen ändrad.SQL> förklara plan för valt antal(*) från count_test;Explained.SQL> välj * från tabell(dbms_xplan.display(null,null,'projektion'));PLAN_TABLE_OUTPUT-------------------------------------- -------------------------------------------------- ---------------------Planens hashvärde:371675025------------------------ -------------------------------------------------- | Id | Operation | Namn | Rader | Kostnad (%CPU)| Tid |------------------------------------------------ --------------------------| 0 | VÄLJ UTTALANDE | | 1 | 589 (2)| 00:00:01 || 1 | SORTERA AGGREGATER | | 1 | | || 2 | INDEX FAST FULL SCAN| COUNT_PK | 848K| 589 (2)| 00:00:01 |------------------------------------------------ ------------------------------ Kolumnprojektionsinformation (identifierad med operations-id):----------- -------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 2 - (raduppsättning=1019)Obs----- - dynamisk statistik använd:dynamisk sampling (nivå=2)19 rader valda.SQL>SQL>SQL> alter sessionsuppsättningshändelser ='10053 spåra namnkontext för alltid, nivå 2';Session ändrad.SQL> välj count(rowid) från count_test;COUNT(ROWID)------ 1000000SQL> ändra sessionsuppsättningshändelser ='10053 spåra namnkontext av';Session ändrad.SQL> förklara plan för urval count(rovid) från count_test;Explained.SQL> välj * från tabell(dbms_xplan.display(null,null,'projektion'));PLAN_TABLE_OUTPUT- -------------------------------------------------- ---------------------------------------Planens hashvärde:371675025------ -------------------------------------------------- --------------------------| Id | Operation | Namn | Rader | Bytes | Kostnad (%CPU)| Tid |------------------------------------------------ ----------------------------------| 0 | VÄLJ UTTALANDE | | 1 | 12 | 589 (2)| 00:00:01 || 1 | SORTERA AGGREGATER | | 1 | 12 | | || 2 | INDEX FAST FULL SCAN| COUNT_PK | 848K| 9941K| 589 (2)| 00:00:01 |------------------------------------------------ -------------------------------------- Kolumnprojektionsinformation (identifierad med operations-id):-- -------------------------------------------------- ------- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Obs----- - dynamisk statistik använd:dynamisk sampling (nivå =2)19 rader valda.SQL>SQL> spool offcommit;

10053-spårningsdetaljerna ändrades inte efter att primärnyckeln lades till.

Det verkar som om två delar av information har hämtats från detta experiment — count(rowid) är inte bättre än count(*) när tabeller innehåller CLOB-kolumner och att count(*) inte utökar kolumnlistan som "select *" gör (och det finns ingen anledning att tro att det skulle göra det).

Beviset finns i puddingen, som det gamla ordspråket lyder.

# # #

Se artiklar avDavid Fitzjarrell


  1. Hur make_timestamp() fungerar i PostgreSQL

  2. Prestanda överraskningar och antaganden:DATEADD

  3. MySQL 8 vanliga tabelluttryck CTE

  4. Installera pg gem; FEL:Det gick inte att bygga ädelstensinbyggt tillägg