Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Czy COUNT(rowid) jest szybszy niż COUNT(*)?

Od dawna dyskusja na forach i grupach dyskusyjnych Oracle dotyczy efektywności użycia count(*) do zwracania liczby wierszy z danej tabeli. Nowa zmarszczka w tej dyskusji wprowadza teraz count(rowid) jako bardziej wydajną alternatywę; argument stwierdza, że ​​count(*) rozszerza całą listę kolumn, podobnie jak „select * …” i jako taki może być ujściem zasobów, gdy kolumny CLOB są obecne w żądanej tabeli. Przyjrzyjmy się temu argumentowi i zobaczmy, czy ma sens. Zacznijmy od utworzenia i wypełnienia tabeli zawierającej kolumnę CLOB:

SQL>
SQL> create table count_test(
  2  id      number,
  3  val     varchar2(40),
  4  clb     clob);

Table created.

SQL>
SQL> begin
  2          for z in 1..1000000 loop
  3             insert into count_test
  4             values(z, 'Record '||z, 'Clob value '||z);
  5          end loop;
  6
  7          commit;
  8  end;
  9  /

PL/SQL procedure successfully completed.

SQL>

Następnie ustawmy zdarzenie 10053, aby zrzucić ślad optymalizatora, abyśmy mogli zobaczyć, jak Oracle planuje wykonać zapytania count():

SQL> alter session set events = '10053 trace  name context forever, level 2';

Session altered.

Scena jest gotowa, uruchommy kilka wariantów count(), aby zobaczyć, jak zachowuje się Oracle. Najpierw wykonamy proste liczenie(*) i wyświetlimy plan:

SQL> select count(*) from count_test;

  COUNT(*)
----------
   1000000

SQL> alter session set events = '10053 trace name context off';

Session altered.

SQL> explain plan for select count(*) from count_test;

Explained.

SQL> select * from table(dbms_xplan.display(null,null,'projection'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------
Plan hash value: 371675025

----------------------------------------+-----------------------------------+
| Id  | Operation           | Name      | Rows  | Bytes | Cost  | Time      |
----------------------------------------+-----------------------------------+
| 0   | SELECT STATEMENT    |           |       |       |  3582 |           |
| 1   |  SORT AGGREGATE     |           |     1 |       |       |           |
| 2   |   TABLE ACCESS FULL | COUNT_TEST|  848K |       |  3582 |  00:00:43 |
----------------------------------------+-----------------------------------+      
Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) COUNT(*)[22]
   2 - (rowset=1019)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

19 rows selected.

SQL>

Patrząc na wygenerowany plik śledzenia, Oracle po prostu używa count(*) bez zmian, aby zwrócić wyniki:

Final query after transformations:******* UNPARSED QUERY IS *******
SELECT COUNT(*) "COUNT(*)" FROM "BING"."COUNT_TEST" "COUNT_TEST"          
...
----- Explain Plan Dump -----
----- Plan Table -----
============
Plan Table
============
----------------------------------------+-----------------------------------+
| Id  | Operation           | Name      | Rows  | Bytes | Cost  | Time      |
----------------------------------------+-----------------------------------+
| 0   | SELECT STATEMENT    |           |       |       |  3582 |           |
| 1   |  SORT AGGREGATE     |           |     1 |       |       |           |
| 2   |   TABLE ACCESS FULL | COUNT_TEST|  848K |       |  3582 |  00:00:43 |
----------------------------------------+-----------------------------------+                 
Query Block Name / Object Alias (identified by operation id):
------------------------------------------------------------
1 - SEL$1
2 - SEL$1                / "COUNT_TEST"@"SEL$1"
------------------------------------------------------------
Predicate Information:
------------------------

SQL>

Żadnych niespodzianek; zauważ, że Oracle nie rozszerza „*” na wszystkie kolumny w tabeli — „*” w tym przypadku oznacza, że ​​mają być liczone wszystkie wiersze. Gdyby podano rzeczywistą nazwę kolumny, Oracle zliczyłoby wartości w określonej kolumnie. Przyjrzyjmy się teraz, co Oracle robi z zapytaniem count(rowid):

SQL> alter session set events = '10053 trace  name context forever, level 2';

Session altered.

SQL> select count(rowid) from count_test;

COUNT(ROWID)
------------
     1000000

SQL> alter session set events = '10053 trace name context off';

Session altered.

SQL> explain plan for select count(rowid) from count_test;

Explained.

SQL> select * from table(dbms_xplan.display(null,null,'projection'));

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------
Plan hash value: 371675025

----------------------------------------+-----------------------------------+
| Id  | Operation           | Name      | Rows  | Bytes | Cost  | Time      |
----------------------------------------+-----------------------------------+
| 0   | SELECT STATEMENT    |           |       |       |  3582 |           |
| 1   |  SORT AGGREGATE     |           |     1 |    12 |       |           |
| 2   |   TABLE ACCESS FULL | COUNT_TEST|  848K | 9941K |  3582 |  00:00:43 |
----------------------------------------+-----------------------------------+           

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) COUNT(ROWID)[22]
   2 - (rowset=256) ROWID[ROWID,10]

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

19 rows selected.

SQL>

Oracle generuje wartość rowid dla każdego wiersza w tabeli, operacja, która zużywa część zasobów procesora. Ponieważ zapytanie powróciło mniej więcej w tym samym czasie, co wersja count(*), „trafienie” wydajności wydaje się być znikome. Dodanie klucza podstawowego nieznacznie zmienia plany, ale nie tekst zapytania:


SQL> alter table count_test add constraint count_pk primary key(id);

Table altered.                                                                                                                            
SQL>
SQL> alter session set events = '10053 trace  name context forever, level 2';

Session altered.

SQL> select count(*) from count_test;

  COUNT(*)
----------
   1000000

SQL> alter session set events = '10053 trace name context off';

Session altered.

SQL> explain plan for select count(*) from count_test;

Explained.

SQL> select * from table(dbms_xplan.display(null,null,'projection'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------
Plan hash value: 371675025

--------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |     1 |   589   (2)| 00:00:01 |
|   1 |  SORT AGGREGATE       |          |     1 |            |          |
|   2 |   INDEX FAST FULL SCAN| COUNT_PK |   848K|   589   (2)| 00:00:01 |
--------------------------------------------------------------------------        

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) COUNT(*)[22]
   2 - (rowset=1019)

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

19 rows selected.

SQL>
SQL>
SQL> alter session set events = '10053 trace  name context forever, level 2';

Session altered.

SQL> select count(rowid) from count_test;

COUNT(ROWID)
------------
     1000000

SQL> alter session set events = '10053 trace name context off';

Session altered.

SQL> explain plan for select count(rowid) from count_test;

Explained.

SQL> select * from table(dbms_xplan.display(null,null,'projection'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------
Plan hash value: 371675025

----------------------------------------------------------------------------------
| Id  | Operation             | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |     1 |    12 |   589   (2)| 00:00:01 |
|   1 |  SORT AGGREGATE       |          |     1 |    12 |            |          |
|   2 |   INDEX FAST FULL SCAN| COUNT_PK |   848K|  9941K|   589   (2)| 00:00:01 |
----------------------------------------------------------------------------------                 
Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (#keys=0) COUNT(ROWID)[22]
   2 - (rowset=256) ROWID[ROWID,10]

Note
-----
   - dynamic statistics used: dynamic sampling (level=2)

19 rows selected.

SQL>
SQL> spool off
commit;

Szczegóły śledzenia 10053 nie zmieniły się po dodaniu klucza podstawowego.

Wygląda na to, że w tym eksperymencie zebrano dwie informacje — count(rowid) nie jest lepsza niż count(*), gdy tabele zawierają kolumny CLOB, a licznik(*) nie rozszerza listy kolumn, tak jak robi to „wybierz *”. (i nie ma powodu sądzić, że powinno).

Dowód jest w budyniu, jak mówi stare przysłowie.

# # #

Zobacz artykuły Davida Fitzjarrella


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Utwórz widok przestawny w SQL z tabeli SQL

  2. Jak Java dla OS X 2013-004 wpływa (przerwa) na aplikacje Swing?

  3. Włączanie TLS w R12.1

  4. jak dodać drugi znacznik czasu oracle

  5. Jak zaktualizować Oracle Clob za pomocą JDBC?