Типы данных UROWID
и ROWID
предназначены для работы с идентификаторами строк базы данных. ROWID
— идентификатор строки (ROW IDentifier), а точнее, двоичное значение, однозначно идентифицирующее строку данных в таблице Oracle, даже если таблица не имеет уникального ключа. Две записи, даже если они содержат одинаковые значения столбцов, обладают разными идентификаторами ROWID
или UROWID
.
Учтите, что значения ROWID
в таблицах могут изменяться. В ранних версиях Oracle (Oracle8 и ранее) значения ROWIDs
оставались неизменными на протяжении жизненного цикла строки. Но в версии Oracle8i
были добавлены новые возможности, нарушающие это старое правило. Если для обычной или индексной таблицы разрешено перемещение строк, обновление может привести к изменению ROWID
или UROWID
строки. Кроме того, если с таблицей будет выполнена операция, из-за которой строка перейдет из одного физического блока данных в другой блок, значение ROWID
строки изменится.
Впрочем, даже с учетом этого предупреждения значения ROWID
приносят практическую пользу. Включение значений ROWID
в командах SELECT, UPDATE, MERGE
и DELETE
в некоторых случаях повышает скорость обработки, поскольку обращение к строке по ее идентификатору выполняется быстрее, чем по первичному ключу. На рис. 1 использование ROWID
в команде UPDATE
сравнивается с использованием значений столбцов (например, первичного ключа).
Рис. 1. Идентификатор ROWID ссылается непосредственно на строку таблицы
Исторически тип ROWID
появился раньше типа UROWID
. По мере добавления новых функциональных возможностей, таких как использование индекс-таблиц и шлюзов к другим базам данных, компания Oracle, естественно, разрабатывала и новые типы идентификаторов строк, и новые типы данных для их хранения. Так появился тип данных UROWID
, используемый для хранения идентификаторов строк таблиц любого типа. Буква U
в его названии означает «Universal
» (универсальный), а переменная UROWID
может содержать любое значение ROWID
из любого типа таблиц.
Тип данных UROWID
рекомендуется использовать во всех новых программах, работающих с идентификаторами строк. Тип ROWID
обеспечивает обратную совместимость, но он не поддерживает все типы идентификаторов строк, использующихся в современных базах данных Oracle. Тип UROWID
надежнее — он поддерживает все типы ROWID
, сохраняя все преимущества ускоренного доступа.
Получение идентификаторов строк
Чтобы получить ROWID
для строки таблицы, добавьте ключевое слово в список выборки.
Пример:
DECLARE
employee_rowid UROWID;
employee_salary NUMBER;
BEGIN
-- Выборка информации, которую мы собираемся модифицировать
SELECT rowid, salary INTO employee_rowid, employee_salary
FROM employees
WHERE last_name='Grubbs' AND first_name='John';
END;
В терминологии Oracle ROWID
называется «псевдостолбцом», потому что на самом деле столбца с именем ROWID
в таблице не существует. Значение ROWID
ближе к указателю — оно содержит физический адрес строки в таблице.
Использование идентификаторов строк
Преимущества использования ROWID
проявляются при повторном обращении к строке, если оно производится часто или сопряжено со значительными затратами ресурсов. Вспомните пример из предыдущего раздела, когда мы извлекали из базы данных информацию об окладе работника. Допустим, нам потребовалось изменить величину оклада и ввести в базу данных новое значение. Конечно, для этого можно написать команду UPDATE
с тем же условием WHERE
, которое использовалось в команде SELECT
:
DECLARE
employee_rowid UROWID;
employee_salary NUMBER;
BEGIN
-- Выборка информации, которую мы собираемся модифицировать
SELECT rowid, salary INTO employee_rowid, employee_salary
FROM employees
WHERE last_name='Grubbs' AND first_name='John';
/* Вычисление нового оклада */
UPDATE employees
SET salary = employee_salary
WHERE last_name='Grubbs' AND first_name='John';
END;
Конечно, этот код работает, но у него есть недостаток: необходимость повторения для UPDATE
пути доступа, который уже использовался для SELECT
. Скорее всего, поиск нужной записи потребовал обращения к одному-двум индексам. Но ведь программа уже обращалась к этим индексам для команды SELECT
, так зачем выполнять всю работу дважды? Обращение к индексу производилось для получения ROWID
с целью прямого обращения к записи. Включая значение ROWID
в команду SELECT
, я могу просто передать его команде UPDATE
и обойтись без лишнего поиска по индексу:
DECLARE
employee_rowid UROWID;
employee_salary NUMBER;
BEGIN
-- Выборка информации, которую мы собираемся модифицировать
SELECT rowid, salary INTO employee_rowid, employee_salary
FROM employees
WHERE last_name='Grubbs' AND first_name='John';
/* Вычисление нового оклада */
UPDATE employees
SET salary = employee_salary
WHERE rowid = employee_rowid;
END;
Вспомните предупреждение о возможном изменении ROWID
. Если в многопользовательской системе ROWID
строки изменятся между командами SELECT
и UPDATE
, то код не будет работать так, как задумано. Почему? Потому что при разрешенном перемещении строк в стандартной таблице ROWID
этой строки таблицы может измениться. А перемещение строк может быть разрешено потому, что администратор базы данных желает провести оперативную реорганизацию таблицы, или таблица может быть разбита на блоки, и перемещение строки позволит записи переместиться из одного блока в другой в процессе обновления.
Иногда для достижения аналогичного результата проще всего воспользоваться для выборки данных явным курсором, с последующей модификацией или удалением с применением конструкции WHERE CURRENT OF CURSOR
.
Конечно, использование ROWID
ускоряет работу программ PL/SQL, потому что вы по сути опускаетесь на физический уровень управления базой данных. Однако хорошие приложения обычно не зависят от физической структуры данных. Они поручают управление физической структурой базе данных и административным программам, а сами ограничиваются логическим управлением данными. По этой причине использовать ROWID
в приложениях обычно не рекомендуется.