Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Apakah COUNT(rowid) Lebih Cepat Dari COUNT(*)?

Diskusi lama di forum Oracle dan newsgroup adalah efisiensi penggunaan count(*) untuk mengembalikan jumlah baris dari tabel yang diberikan. Kerutan baru dalam diskusi itu sekarang memperkenalkan count(rowid) sebagai alternatif yang lebih efisien; argumen menyatakan bahwa count(*) memperluas seluruh daftar kolom, seperti "pilih * ...", dan, dengan demikian, bisa menjadi sumber daya saat kolom CLOB ada di tabel yang diinginkan. Mari kita lihat argumen itu dan lihat apakah itu menahan air. Mari kita mulai dengan membuat dan mengisi tabel yang berisi kolom CLOB:

SQL>SQL> buat tabel count_test( 2 nomor id, 3 val varchar2(40), 4 clb clob);Tabel dibuat.SQL>SQL> mulai 2 untuk z dalam 1..1000000 loop 3 masukkan ke dalam nilai count_test 4 (z, 'Rekam '||z, 'Nilai gumpalan '||z); 5 ujung lingkaran; 6 7 komit; 8 akhir; 9 /PL/SQL prosedur berhasil diselesaikan.SQL>

Selanjutnya mari kita atur event 10053 untuk membuang jejak pengoptimal sehingga kita dapat melihat bagaimana Oracle berencana untuk mengeksekusi query count():

SQL> alter session set events ='10053 melacak nama konteks selamanya, level 2';Sesi diubah.

Tahap sudah diatur, mari kita jalankan beberapa varian count() untuk melihat bagaimana Oracle berperilaku. Pertama, kita akan melakukan penghitungan langsung (*) dan menampilkan rencananya:

SQL> pilih count(*) dari count_test; COUNT(*)---------- 1000000SQL> alter session set events ='10053 trace name context off';Sesi diubah.SQL> jelaskan rencana untuk jumlah terpilih(*) dari count_test;Explained.SQL> pilih * dari tabel(dbms_xplan.display(null,null,'projection'));PLAN_TABLE_OUTPUT-------------------- -------------------------------------------------- ------------------------- Rencanakan nilai hash:371675025-------------------- --------------------+---------------------------- ------+| ID | Operasi | Nama | Baris | Byte | Biaya | Waktu |-----------------------------------------+------- ----------------------------+| 0 | PILIH PERNYATAAN | | | | 3582 | || 1 | SORT AGREGAT | | 1 | | | || 2 | AKSES TABEL PENUH | COUNT_TEST| 848K | | 3582 | 00:00:43 |---------------------------------------+--- --------------------------------+ Informasi Proyeksi Kolom (diidentifikasi dengan id operasi):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(*)[22] 2 - (rowset=1019)Catatan----- - statistik dinamis yang digunakan:pengambilan sampel dinamis (level=2)19 baris dipilih.SQL> 

Melihat file jejak yang dihasilkan Oracle cukup menggunakan count(*) apa adanya untuk mengembalikan hasilnya:

Kueri terakhir setelah transformasi:******* PERMINTAAN YANG TIDAK DIPARASI ADALAH *******PILIH COUNT(*) "COUNT(*)" FROM "BING"."COUNT_TEST" "COUNT_TEST" ... ----- Jelaskan Plan Dump ---------- Plan Table -----============Plan Table=============-----------------------------------------+-------- ---------------------------+| ID | Operasi | Nama | Baris | Byte | Biaya | Waktu |-----------------------------------------+------- ----------------------------+| 0 | PILIH PERNYATAAN | | | | 3582 | || 1 | SORT AGREGAT | | 1 | | | || 2 | AKSES TABEL PENUH | COUNT_TEST| 848K | | 3582 | 00:00:43 |---------------------------------------+--- --------------------------------+ Nama Blok Kueri / Alias ​​Objek (diidentifikasi dengan id operasi):---- -------------------------------------------------- ------1 - SEL$12 - SEL$1 / "COUNT_TEST"@"SEL$1"---------------------------- -------------------------------- Informasi Predikat:--------------- ---------SQL>

Tidak ada kejutan di sana; perhatikan bahwa Oracle tidak memperluas "*" ke semua kolom dalam tabel — "*" dalam hal ini menunjukkan bahwa semua baris harus dihitung. Jika nama kolom yang sebenarnya telah diberikan maka Oracle akan menghitung nilai dalam kolom yang ditentukan. Sekarang mari kita lihat apa yang dilakukan Oracle dengan query count(rowid):

SQL> ubah rangkaian acara sesi ='10053 lacak konteks nama selamanya, level 2';Sesi diubah.SQL> pilih count(rowid) dari count_test;COUNT(ROWID)------------ 1000000SQL> ubah sesi set acara ='10053 lacak konteks nama mati';Sesi diubah.SQL> jelaskan rencana untuk jumlah pilihan(rowid) dari count_test;Explained.SQL> pilih * dari tabel(dbms_xplan.display(null,null,'projection) '));PLAN_TABLE_OUTPUT-------------------------------------------------------- -------------------------------------------------- ---- Rencanakan nilai hash:371675025-----------------------------------------+ -----------------------------------+| ID | Operasi | Nama | Baris | Byte | Biaya | Waktu |-----------------------------------------+------- ----------------------------+| 0 | PILIH PERNYATAAN | | | | 3582 | || 1 | SORT AGREGAT | | 1 | 12 | | || 2 | AKSES TABEL PENUH | COUNT_TEST| 848K | 9941K | 3582 | 00:00:43 |---------------------------------------+--- --------------------------------+ Informasi Proyeksi Kolom (diidentifikasi dengan id operasi):------- -------------------------------------------------- -- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Catatan----- - statistik dinamis yang digunakan:dynamic sampling (level=2)19 baris dipilih.SQL>

Oracle menghasilkan nilai rowid untuk setiap baris dalam tabel, sebuah operasi yang akan menggunakan beberapa sumber daya CPU. Karena kueri kembali dalam waktu yang hampir bersamaan dengan versi count(*), kinerja 'hit' tampaknya dapat diabaikan. Menambahkan kunci utama mengubah rencana sedikit tetapi bukan teks kueri:

SQL> ubah tabel count_test tambahkan batasan count_pk primary key(id);Tabel diubah. SQL>SQL> ubah sesi set peristiwa ='10053 jejak nama konteks selamanya, level 2';Sesi diubah.SQL> pilih count(*) dari count_test; COUNT(*)---------- 1000000SQL> alter session set events ='10053 trace name context off';Sesi diubah.SQL> jelaskan rencana untuk jumlah terpilih(*) dari count_test;Explained.SQL> pilih * dari tabel(dbms_xplan.display(null,null,'projection'));PLAN_TABLE_OUTPUT-------------------- -------------------------------------------------- ----------Nilai hash rencana:371675025------------------------ -------------------------------------------------- | ID | Operasi | Nama | Baris | Biaya (%CPU)| Waktu |------------------------------------------------ --------------------------| 0 | PILIH PERNYATAAN | | 1 | 589 (2)| 00:00:01 || 1 | SORT AGREGAT | | 1 | | || 2 | INDEKS PEMINDAI LENGKAP CEPAT| COUNT_PK | 848K| 589 (2)| 00:00:01 |--------------------------------------------- ------------------------------ Informasi Proyeksi Kolom (diidentifikasi dengan id operasi):---------- -------------------------------------------------- 1 - (#keys=0) COUNT(*)[22] 2 - (rowset=1019)Catatan----- - statistik dinamis yang digunakan:sampling dinamis (level=2)19 baris dipilih.SQL>SQL>SQL> alter peristiwa set sesi ='10053 melacak konteks nama selamanya, level 2';Sesi diubah.SQL> pilih count(rowid) dari count_test;COUNT(ROWID)------------ 1000000SQL> ubah peristiwa set sesi ='10053 trace name context off';Sesi diubah.SQL> jelaskan rencana untuk jumlah pilih(rowid) dari count_test;Dijelaskan.SQL> pilih * dari tabel(dbms_xplan.display(null,null,'projection'));PLAN_TABLE_OUTPUT- -------------------------------------------------- --------------------------------------- Rencanakan nilai hash:371675025------ -------------------------------------------------- --------------------------| ID | Operasi | Nama | Baris | Byte | Biaya (%CPU)| Waktu |------------------------------------------------ ----------------------------------| 0 | PILIH PERNYATAAN | | 1 | 12 | 589 (2)| 00:00:01 || 1 | SORT AGREGAT | | 1 | 12 | | || 2 | INDEKS PEMINDAI LENGKAP CEPAT| COUNT_PK | 848K| 9941K| 589 (2)| 00:00:01 |--------------------------------------------- --------------------------------------- Informasi Proyeksi Kolom (diidentifikasi dengan id operasi):-- -------------------------------------------------- ------- 1 - (#keys=0) COUNT(ROWID)[22] 2 - (rowset=256) ROWID[ROWID,10]Catatan----- - statistik dinamis yang digunakan:dynamic sampling (level =2)19 baris dipilih.SQL>SQL> spool offcommit;

Detail jejak 10053 tidak berubah setelah kunci utama ditambahkan.

Tampaknya dua informasi telah diperoleh dari percobaan ini — count(rowid) tidak lebih baik daripada count(*) ketika tabel berisi kolom CLOB dan count(*) tidak memperluas daftar kolom seperti yang dilakukan "select *" (dan tidak ada alasan untuk percaya bahwa itu seharusnya).

Buktinya ada di puding, seperti pepatah lama.

# # #

Lihat artikel oleh David Fitzjarrell


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. EF dan TransactionScope untuk SQL Server dan Oracle tanpa meningkatkan/mencakup ke DTC?

  2. Metode Pengumpulan:Prosedur HAPUS Dalam Database Oracle

  3. 12.2 Fitur Baru RAC/GI

  4. menginstal Oracle Instantclient di Mac OS/X tanpa mengatur variabel lingkungan?

  5. Tentang Elemen Format V di Oracle