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

Indeks waktu-konstan untuk kolom string pada database Oracle

Cluster hash dapat menyediakan O(1) waktu akses, tetapi tidak O(1) waktu penegakan kendala. Namun, dalam praktiknya, waktu akses konstan dari cluster hash lebih buruk daripada waktu akses O(log N) dari indeks b-tree biasa. Selain itu, cluster lebih sulit untuk dikonfigurasi dan tidak dapat diskalakan dengan baik untuk beberapa operasi.

Buat Cluster Hash

drop table orders_cluster;
drop cluster cluster1;

create cluster cluster1
(
    MerchantID number,
    TransactionID varchar2(20)
)
single table hashkeys 10000; --This number is important, choose wisely!

create table orders_cluster
(
    id number,
    MerchantID number,
    TransactionID varchar2(20)
) cluster cluster1(merchantid, transactionid);

--Add 1 million rows.  20 seconds.
begin
    for i in 1 .. 10 loop
        insert into orders_cluster
        select rownum + i * 100000, mod(level, 100)+ i * 100000, level
        from dual connect by level <= 100000;
        commit;
    end loop;
end;
/

create unique index orders_cluster_idx on orders_cluster(merchantid, transactionid);

begin
    dbms_stats.gather_table_stats(user, 'ORDERS_CLUSTER');
end;
/

Buat Tabel Reguler (Untuk Perbandingan)

drop table orders_table;

create table orders_table
(
    id number,
    MerchantID number,
    TransactionID varchar2(20)
) nologging;

--Add 1 million rows.  2 seconds.
begin
    for i in 1 .. 10 loop
        insert into orders_table
        select rownum + i * 100000, mod(level, 100)+ i * 100000, level
        from dual connect by level <= 100000;
        commit;
    end loop;
end;
/

create unique index orders_table_idx on orders_table(merchantid, transactionid);

begin
    dbms_stats.gather_table_stats(user, 'ORDERS_TABLE');
end;
/

Contoh Jejak

SQL*Plus Autotrace adalah cara cepat untuk menemukan rencana penjelasan dan melacak aktivitas I/O per pernyataan. Jumlah permintaan I/O diberi label sebagai "consistent get" dan merupakan cara yang layak untuk mengukur jumlah pekerjaan yang dilakukan. Kode ini menunjukkan bagaimana angka dihasilkan untuk bagian lain. Kueri sering kali perlu dijalankan lebih dari sekali untuk menghangatkan suasana.

SQL> set autotrace on;
SQL> select * from orders_cluster where merchantid = 100001 and transactionid = '2';

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 621801084

------------------------------------------------------------------------------------
| Id  | Operation         | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                |     1 |    16 |     1   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS HASH| ORDERS_CLUSTER |     1 |    16 |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("MERCHANTID"=100001 AND "TRANSACTIONID"='2')


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         31  consistent gets
          0  physical reads
          0  redo size
        485  bytes sent via SQL*Net to client
        540  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          0  rows processed

SQL>

Temukan Hashkey Optimal, Trade-Off

Untuk kinerja baca yang optimal, semua tabrakan hash harus muat dalam satu blok (semua Oracle I/O dilakukan per blok, biasanya 8K). Mendapatkan hak penyimpanan yang ideal itu rumit dan membutuhkan pengetahuan tentang algoritma hash, ukuran penyimpanan (tidak sama dengan ukuran blok), dan jumlah kunci hash (ember). Oracle memiliki algoritma dan ukuran default sehingga memungkinkan untuk fokus hanya pada satu atribut, jumlah kunci hash.

Lebih banyak kunci hash menyebabkan lebih sedikit tabrakan. Ini bagus untuk kinerja TABLE ACCESS HASH karena hanya ada satu blok untuk dibaca. Di bawah ini adalah jumlah yang konsisten untuk ukuran hashkey yang berbeda. Sebagai perbandingan, akses indeks juga disertakan. Dengan hashkey yang cukup, jumlah blok berkurang ke jumlah optimal, 1.

Method          Consistent Gets (for transactionid = 1, 20, 300, 4000, and 50000)
Index           4,  3,  3,  3,  3
Hashkeys 100    1, 31, 31, 31, 31
Hashkeys 1000   1,  3,  4,  4,  4
Hashkeys 10000  1,  1,  1,  1,  1

Lebih banyak kunci hash juga menghasilkan lebih banyak ember, lebih banyak ruang yang terbuang, dan operasi PENUH AKSES TABEL yang lebih lambat.

Table type      Space in MB
HeapTable       24MB
Hashkeys 100    26MB
hashkeys 1000   30MB
hashkeys 10000  81MB

Untuk mereproduksi hasil saya, gunakan contoh kueri seperti select * from orders_cluster where merchantid = 100001 and transactionid = '1'; dan ubah nilai terakhir menjadi 1, 20, 300, 4000, dan 50000.

Perbandingan Kinerja

Hasil yang konsisten dapat diprediksi dan mudah diukur, tetapi pada akhirnya hanya waktu jam dinding yang penting. Anehnya, akses indeks dengan 4 kali lebih konsisten masih lebih cepat daripada skenario cluster hash yang optimal.

--3.5 seconds for b-tree access.
declare
    v_count number;
begin
    for i in 1 .. 100000 loop
        select count(*)
        into v_count
        from orders_table
        where merchantid = 100000 and transactionid = '1';
    end loop;
end;
/

--3.8 seconds for hash cluster access.
declare
    v_count number;
begin
    for i in 1 .. 100000 loop
        select count(*)
        into v_count
        from orders_cluster
        where merchantid = 100000 and transactionid = '1';
    end loop;
end;
/

Saya juga mencoba tes dengan predikat variabel tetapi hasilnya serupa.

Apakah Skalanya?

Tidak, kluster hash tidak berskala. Terlepas dari kompleksitas waktu O(1) TABLE ACCESS HASH, dan kompleksitas waktu O(log n) dari INDEX UNIQUE SCAN, cluster hash sepertinya tidak pernah mengungguli indeks b-tree.

Saya mencoba kode sampel di atas dengan 10 juta baris. Cluster hash sangat lambat untuk dimuat, dan masih di bawah kinerja indeks pada kinerja SELECT. Saya mencoba menskalakannya hingga 100 juta baris tetapi penyisipannya akan memakan waktu 11 hari.

Kabar baiknya adalah bahwa b*trees dapat berkembang biak dengan baik. Menambahkan 100 juta baris ke contoh di atas hanya membutuhkan 3 level dalam indeks. Saya melihat semua DBA_INDEXES untuk lingkungan basis data yang besar (ratusan basis data dan satu petabyte data) - indeks terburuk hanya memiliki 7 level. Dan itu adalah indeks patologis pada VARCHAR2(4000) kolom. Dalam kebanyakan kasus, indeks b-tree Anda akan tetap dangkal terlepas dari ukuran tabel.

Dalam hal ini, O(log n) mengalahkan O(1).

Tapi MENGAPA?

Kinerja klaster hash yang buruk mungkin merupakan korban dari upaya Oracle untuk menyederhanakan berbagai hal dan menyembunyikan jenis detail yang diperlukan untuk membuat klaster hash berfungsi dengan baik. Cluster sulit diatur dan digunakan dengan benar dan jarang memberikan manfaat yang signifikan. Oracle belum melakukan banyak upaya dalam beberapa dekade terakhir.

Para komentator benar bahwa indeks b-tree sederhana adalah yang terbaik. Tetapi tidak jelas mengapa hal itu harus benar dan ada baiknya untuk memikirkan tentang algoritme yang digunakan dalam database.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Mengubah objek menjadi CLOB

  2. Oracle SQL Hierarchical Query:Meratakan Hirarki dan Melakukan Agregasi

  3. Kode sql untuk membuat gambar Cermin dari string di Oracle sql

  4. Fungsi NLS_UPPER() di Oracle

  5. Hubungan pendek Oracle CASE tidak bekerja dalam grup oleh