Firebird РУКОВОДСТВО РАЗРАБОТЧИКА БАЗ ДАННЫХ
Шрифт:
Кандидат в первичные ключи, который может быть одним столбцом или группой столбцов, имеет два обязательных требования.
* Атрибут NOT NULL должен быть объявлен для всех столбцов в группе из одного или более столбцов. Целостность ключа может быть осуществлена только сравнением значений, a NULL не является значением.
* Столбец или группа столбцов должны быть уникальными - т. е. не может в таблице появиться более одной строки с теми же значениями. Например, номер водительских прав или социального обеспечения могут рассматриваться как
К этим теоретическим "установкам" должна быть добавлена третья.
* Общий размер кандидата в ключи должен быть 252 байта или меньше. Дело здесь не просто в подсчете символов. Этот лимит должен быть уменьшен - в некоторых случаях радикально - если присутствует несколько столбцов, недвоичная последовательность сортировки или многобайтовый набор символов.
Используя таблицу EMPLOYEE базы данных employee.fdb из каталога /examples корневого каталога Firebird (employee.gdb в версии 1,0.x), давайте посмотрим, как реальные данные могут привести к ошибочности ваших теоретических предположений об уникальности. Вот объявление, которое показывает имеющие смысл данные, хранимые в этой таблице:
CREATE TABLE EMPLOYEE (
FIRST_NAME VARCHAR(15) NOT NULL,
/* предположение: служащий должен иметь имя */
LAST_NAME VARCHAR(20) NOT NULL,
/* предположение: служащий должен иметь фамилию */
PHONE_EXT VARCHAR(4),
HIRE_DATE DATE DEFAULT CURRENT_DATE NOT NULL,
DEPT_NO CHAR(3) NOT NULL,
JOB_CODE VARCHAR (5) NOT NULL,
JOB_GRADE SMALLINT NOT NULL,
JOB_COUNTRY VARCHAR(15) NOT NULL,
SALARY NUMERIC (15, 2) DEFAULT 0 NOT NULL,
FULL_NAME COMPUTED BY FIRST_NAME || ' ' || LAST_NAME ) ;
Фактически эта структура не имеет кандидата в ключи. Невозможно идентифицировать одну строку служащего, используя (FIRST_NAME, LAST_NAME) в качестве ключа, поскольку комбинация двух элементов с вероятностью от средней до высокой может дублироваться в организации. Мы не сможем сохранить записи двух служащих с именем John Smith.
Для получения ключей необходимо что-то изобрести. Это "что-то" - механизм, известный как суррогатный ключ.
Мы уже рассматривали суррогатный ключ во вводной теме о ключах в главе 14. Суррогатный первичный ключ - значение, гарантирующее уникальность и не имеющее смыслового содержания, которое используется в качестве заменителя ключа в структуре таблицы, которая не может предоставить кандидата на ключ в собственной структуре. По этой причине в таблицу EMPLOYEE добавляется EMP_NO (объявляется через домен) для выполнения роли суррогатного ключа:
CREATE DOMAIN EMPNO SMALLINT ;
COMMIT;
ALTER TABLE EMPLOYEE
ADD EMP_NO EMPNO NOT NULL,
ADD CONSTRAINT PK_EMPLOYEE
PRIMARY KEY(EMP_NO) ;
Эта
Возможно, вам захочется рассмотреть преимущества использования суррогатного первичного ключа не только в случае, когда таблица не может предложить кандидата, но также и в случаях, где ваш кандидат в ключи является составным.
В процессе анализа данных иногда в структуре данных можно отыскать единственный уникальный столбец. Теория советует найти два или более столбцов, сгруппированных вместе в качестве ключа, которые будут гарантировать уникальность строки. Когда множество столбцов объединяются для формирования ключа, такой ключ называется составным ключом (composite key) или иногда сложным ключом.
Если вы имеете опыт работы с такими СУБД, как Paradox, где использовали составные ключи для реализации иерархических отношений, вам, вероятно, будет тяжело расстаться с мыслью, что вам придется жить без них. Пока еще на практике составные ключи должны рассматриваться очень ограниченно в таких СУБД, как Firebird, где не выполняется проход по физическим индексным структурам на диске для реализации отношений.
В Firebird нет необходимости в составных индексах и, более того, составные индексы создают некоторые проблемы как для разработки, так и для производительности в случае больших таблиц.
* Составные ключи обычно являются составленными из неатомарных элементов ключа- т.е. выбранные столбцы имеют смысловое значение (они являются "значимыми данными") и, несомненно, уязвимы для внешних изменений и ошибок ручного ввода.
* Внешние ключи из других таблиц, которые ссылаются на эту таблицу, будут дублировать каждый элемент составного ключа. Ссылочная целостность подвергается риску при использовании неатомарных ключей. Комбинация неатомарных элементов увеличивает риск.
* Ключи - внешние, так же как и первичные - имеют постоянные индексы. Составные индексы имеют более строгие ограничения по размеру, чем индексы из одного столбца.
* Составные индексы имеют тенденцию к большим размерам. Большие индексы используют больше страниц базы данных, что приводит к тому, что индексные операции (сортировка, соединение и сравнение) выполняются медленнее, чем необходимо.
Рекомендуется на практике не включать в первичные и внешние ключи любые столбцы, имеющие смысл как данные. Это нарушает один из основных принципов проектирования реляционных баз данных- атомарность. Принцип атомарности требует, чтобы каждый элемент данных полностью существовал сам по себе с единым внутренним правилом управления его существованием.