Oracle
 sql >> база данни >  >> RDS >> Oracle

Индекс с постоянно време за колона с низове в база данни на Oracle

Хеш клъстерите могат да предоставят O(1) време за достъп, но не и O(1) време за налагане на ограничения. На практика обаче постоянното време за достъп на хеш клъстер е по-лошо от O(log N) времето за достъп на обикновен индекс на b-дърво. Освен това клъстерите са по-трудни за конфигуриране и не се мащабират добре за някои операции.

Създаване на хеш клъстер

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;
/

Създаване на обикновена таблица (за сравнение)

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;
/

Пример за проследяване

SQL*Plus Autotrace е бърз начин за намиране на плана за обяснение и проследяване на I/O активността на израз. Броят на I/O заявките е означен като "последователно получава" и е приличен начин за измерване на количеството свършена работа. Този код демонстрира как са генерирани числата за други секции. Заявките често трябва да се изпълняват повече от веднъж, за да се затоплят нещата.

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>

Намерете оптимални хеш ключове, компромиси

За оптимална производителност при четене всички хеш колизии трябва да се поберат в един блок (всички I/O на Oracle се извършват на блок, обикновено 8K). Получаването на правилното идеално хранилище е трудно и изисква познаване на хеш алгоритъма, размера на хранилището (не е същият като размера на блока) и броя на хеш ключовете (кофите). Oracle има алгоритъм и размер по подразбиране, така че е възможно да се фокусирате само върху един атрибут, броя на хеш ключовете.

Повече хеш ключове водят до по-малко сблъсъци. Това е добре за ефективността на TABLE ACCESS HASH, тъй като има само един блок за четене. По-долу е броят на последователните получавания за различни размери на хеш ключовете. За сравнение е включен и достъп до индекс. При достатъчно хеш ключове броят на блоковете намалява до оптималния брой, 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

Повече хеш ключове също водят до повече кофи, повече загубено пространство и по-бавна операция TABLE ACCESS FULL.

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

За да възпроизведа моите резултати, използвайте примерна заявка като select * from orders_cluster where merchantid = 100001 and transactionid = '1'; и променете последната стойност на 1, 20, 300, 4000 и 50000.

Сравнение на производителността

Постоянните резултати са предвидими и лесни за измерване, но в края на деня само времето на стенния часовник има значение. Изненадващо, достъпът до индекс с 4 пъти по-последователни получавания е все още по-бърз от оптималния сценарий на хеш клъстера.

--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;
/

Опитах и ​​теста с променливи предикати, но резултатите бяха подобни.

Мащабира ли се?

Не, хеш клъстерите не се мащабират. Въпреки времевата сложност O(1) на TABLE ACCESS HASH и O(log n) времевата сложност на INDEX UNIQUE SCAN, хеш клъстерите никога не изглежда да превъзхождат индексите на b-дърво.

Опитах горния примерен код с 10 милиона реда. Хеш клъстерът беше болезнено бавен за зареждане и все още не представяше индекса при производителност на SELECT. Опитах се да го мащабирам до 100 милиона реда, но вмъкването щеше да отнеме 11 дни.

Добрата новина е, че б*дърветата се мащабират добре. Добавянето на 100 милиона реда към горния пример изисква само 3 нива в индекса. Разгледах всички DBA_INDEXES за среда с голяма база данни (стотици бази данни и петабайт данни) - най-лошият индекс имаше само 7 нива. И това беше патологичен индекс на VARCHAR2(4000) колони. В повечето случаи индексите на вашето b-дърво ще останат плитки, независимо от размера на таблицата.

В този случай O(log n) бие O(1).

Но ЗАЩО?

Лошата производителност на хеш клъстера може би е жертва на опита на Oracle да опрости нещата и да скрие необходимите детайли, за да може хеш клъстерът да работи добре. Клъстерите са трудни за настройка и използване правилно и рядко биха осигурили значителна полза така или иначе. През последните няколко десетилетия Oracle не е положил много усилия в тях.

Коментаторите са прави, че прост индекс на b-дърво е най-добрият. Но не е очевидно защо това трябва да е вярно и е добре да помислим за алгоритмите, използвани в базата данни.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Получаване на AbstractMethodError при създаване на връзка към база данни Oracle9 със сървър Tomcat 8

  2. Изключение на Java Oracle - максималният брой изрази в списък е 1000

  3. Oracle 10g:Извличане на данни (избор) от XML (тип CLOB)

  4. Oracle Database Explorer:безплатно обучение и акредитация

  5. Как да извлека резултат от функцията на база данни на Oracle чрез ODBC?