Программирование >>  Oracle 

1 ... 436 437 438 [ 439 ] 440 441 442 ... 469


1740

Приложение

функцию для генерации суррогатных ключей. Если сохранять возвращаемые этой функцией значения в таблице, при переносе приложения в следующую версию сервера возможны проблемы, поскольку по тем же входным данным будут выдаваться другие значения хеш-функции!

Функция принимает три параметра.

Строку, которую необходимо хешировать.

Базовое число для возвращаемых значений. Если необходимо получить числа в диапазоне от 0 до некоторого числа, надо указать базовое значение 0.

Размер хеш-таблицы. Лучше, если это число будет степенью двойки.

Чтобы продемонстрировать использование функции GET HASH VALUE, я реализую новый тип, HASHTABLETYPE, для поддержки хешей в языке PL/SQL. Он очень похож на PL/SQL-таблицу, проиндексированную не числами, а строками типа VARCHAR2. Обычно элементы PL/SQL-таблицы индексируются целыми числами. Новый же тип PL/SQL-таблицы позволяет индексировать элементы строками. Можно объявлять переменные типа HASHTABLETYPE, помещать (GET) и выбирать (PUT) из них данные. Такого рода таблиц можно создать сколько угодно. Вот спецификация соответствующих типов:

tkyte@TKYTE816>create or replace type myScalarType

2 as object

3 (key varchar2(4000) ,

4 val varchar2(4000)

5 ) ;

Type created.

tkyte@TKYTE816> create or replace type myArrayType

2 as varray(10000) of myScalarType;

Type created.

tkyte@TKYTE816> create or replace type hashTableType

2 as object

4 g hash size number,

5 g hash table myArrayType,

6 g collision cnt number, 7

8 static function new(p hash size in number)

9 return hashTableType,

11 member procedure put(p key in varchar2,

12 p val in varchar2),

14 member function get(p key in varchar2)

15 return varchar2, 16

17 member procedure print stats



Пакет DBMS UTILITY 1741

18 );

19 /

Type created.

Интересная особенность реализации состоит в добавлении статической функции-члена NEW. Это позволит создать собственный конструктор. Специального значения имя NEW не имеет. Это не ключевое слово. Функция NEW просто позволяет объявлять данные типа HASHTABLETYPE следующим образом:

declare

l hashTable hashTableType := hashTableType.new(1024) ;

a не как обычно:

declare

l hashTable hashTableType : =hashTableType(1024 , myArrayType(), 0) ;

Я уверен, что первый вариант надежнее и понятнее второго. Второй вариант вызова раскрывает многие детали реализации (например, то, что используется тип массива, имеется переменная G COLLISION CNT, которой надо задавать значение 0, и т.п.). Пользователям знать об этом не обязательно.

Теперь рассмотрим тело объектного типа:

scott@TKYTE816> create or replace type body hashTableType 2 as

4 - Наш более дружественный конструктор.

6 static function new(p hash size in number)

7 return hashTableType

8 is

9 begin

10 return hashTableType(p hash size, myArrayType(), 0) ;

11 end;

13 member procedure put(p key in varchar2, p val in varchar2)

14 is

15 l hash number :=

16 dbms utility.get hash value(p key, 1, g hash size);

17 begin 18

19 if (p key is null)

20 then

21 raise application error(-20001, Пустой ключ не допускается);

22 end if;

Следующий фрагмент кода определяет, надо ли увеличить таблицу для размещения нового хешированного значения. Если - да, таблица увеличивается до необходимого для добавления индекса размера:

27 if (l hash > nvl( g hash table.count, 0))

28 then



1742 Приложение

g hash table.extend(l hash-nvl(g hash table.count,0) + l); end if;

Нет никакой гарантии, что запись с индексом, полученным при хешировании соответствующего ключа, пуста. При выявлении конфликта мы пытаемся поместить значение в следующий элемент набора. Выполняется до 1000 попыток поместить значение в таблицу. Если все 1000 попыток завершатся неудачно, попытка добавления считается неудачной. Это значит, что размер таблицы недостаточен:

35 for i in 0 .. 1000

36 loop

3 7 - Если мы собираемся выйти за еделы таблицы,

3 8 - сначала надо добавить новый слот.

3 9 if (g hash table.count <= l hash+i)

40 then

41 g hash table.extend;

42 end if;

Следующий фрагмент реализует действие: если слот не используется или ключ уже находится в этом слоте, использовать и вернуть его. Странной кажется проверка того, пуст ли элемент G HASH TABLE или значение G HASH TABLE(L HASH+I).KEY.

Это показывает, что элемент набора может быть пустым (Null) или может содержать объект с пустыми атрибутами:

if (g hash table(l hash+i) is null OR

nvl(g hash table(l hash+i).key,p key) = p key)

then

g hash table(l hash+i) := myScalarType(p key,p val); return; end if;

46 47 48 49

52 53 54 55

56 5 7

58 59

- Иначе увеличить счетчик количества конфликтов - и перейти к слеющему слоту. g collision cnt := g collision cnt+l; end loop;

Если оказались здесь. Увеличьте ее . raise application error(-2 0 0 01.

значит, таблица слишком мала.

слком много хеш-значений в

-> таблице);

63 64 65

67 68

end;

member function get(p key in varchar2) return varchar2 is

l hash

begin

number := dbms utility.get hash value(p key,

1, g hash size) ;

Если необходимо получить значение, мы обращаемся к элементу индекса, в котором это значение хранится, а в случае возникновения конфликта, просматриваем до 1000



1 ... 436 437 438 [ 439 ] 440 441 442 ... 469

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика