Delphirus - прграммирование на delphi
   Все о delphi Delphirus - прграммирование на delphi
blocks.gif
Навигация
 

Главная
Статьи
Базы данных
Графика
Защита
Интернет
Система
Тексты
Мультимедиа
Файлы
Формы и окна
Другое
Советы
Базы данных
Графика
Интернет
Мультимедиа
Система
Тексты
Файлы
Файлы
Исходники
Компоненты
Инфо
Поиск по сайту
Обратная связь
Самое популярное
Аккаунт
Карта сайта

 
 
 

Советы по delphi \ Базы данных \ Таблицы \ Естественные ключи против искусственных ключей

Естественные ключи против искусственных ключей

Страница: 1/2

Данная статья излагает взгляд автора на проблему, регулярно обсуждающуюся в группах новостей, посвящённых разработке приложений с использованием РСУБД.

О сущности проблемы

Каждая запись в таблице, входящей в РСУБД, должна иметь первичный ключ (ПК) - набор атрибутов, уникально идентифицирующий её в таблице. Случай, когда таблица не имеет первичного ключа, имеет право на существование, однако в данной статье не рассматривается.

В качестве первичного ключа может использоваться:

  • Естественный Ключ (ЕК) - набор атрибутов описываемой записью сущности, уникально её идентифицирующий (например, номер паспорта для человека);
  • Суррогатный Ключ (СК) - автоматически сгенерированное поле, никак не связанное с информационным содержанием записи. Обычно в роли СК выступает автоинкрементное поле типа INTEGER.

Есть два мнения:

  • СК должны использоваться, только если ЕК не существует. Если же ЕК существует, то идентификация записи внутри БД осуществляется по имеющемуся ЕК;
  • СК должны добавляться в любую таблицу, на которую существуют ссылки (REFERENCES) из других таблиц, и связи между ними должны организовываться только при помощи СК. Разумеется, поиск записи и представление её пользователю по прежнему производятся на основании ЕК.

Естественно, можно представить себе и некое промежуточное мнение, но сейчас дискуссия ведётся в рамках двух вышеизложенных.

Когда появляются СК

Для понимания места и значения СК рассмотрим этап проектирования, на котором они вводятся в структуру БД, и методику их введения.

Для ясности рассмотрим БД из 2-х отношений - Города (City) и Люди (People) Предполагаем, что город характеризуется Hазванием (Name), все города имеют разные названия, человек характеризуется Фамилией (Family), номером паспорта (Passport) и городом проживания (City). Также полагаем, что каждый человек имеет уникальный номер паспорта. Hа этапе составления инфологической модели БД её структура одинакова и для ЕК и для СК.

CREATE TABLE City(
  name VARCHAR(30) not NULL PRIMARY KEY
);

CREATE TABLE People(
  Passport CHAR(9) not NULL PRIMARY KEY,
  Family VARCHAR(20) not NULL,
  City VARCHAR(30) not NULL REFERENCES City(name)
);

Для ЕК все готово. Для СК делаем еще один этап и преобразуем таблицы следующим образом:

CREATE TABLE City(
  /*
  В разных диалектах языка SQL автоинкрементное поле будет выражено по-разному -
  например, через IDENTITY, SEQUENCE или GENERATOR.
  Здесь мы используем условное обозначение AUTOINCREMENT.
  */
  Id INT not NULL AUTOINCREMENT PRIMARY KEY
  name VARCHAR(30) not NULL UNIQUE
);

CREATE TABLE People(
  Id INT not NULL AUTOINCREMENT PRIMARY KEY,
  Passport CHAR(9) not NULL UNIQUE,
  Family VARCHAR(20) not NULL,
  CityId INT not NULL REFERENCES City(Id)
);

Обращаю внимание, что:

Все условия, диктуемые предметной областью (уникальность имени города и номера паспорта) продолжают присутствовать в БД, только обеспечиваются не условием PRIMARY KEY, а условием UNIQUE;

Ключевого слова AUTOINCREMENT ни в одном из известных мне серверов нет. Это просто обозначение, что поле генерируется автоматически.

В общем случае алгоритм добавления СК выглядит следующим образом:

  • В таблицу добавляется поле INTEGER AUTOINCREMENT;
  • Оно объявляется PRIMARY KEY;
  • Старый PRIMARY KEY (ЕК) заменяется на UNIQUE CONSTRAINT ;

Если в таблице есть REFERENCES на другие таблицы, то поля, входящие в REFERENCES, заменяются на одно поле типа INTEGER, составляющее первичный ключ (как People.City заменена на People.CityId).

Это механическая операция, которая никак не нарушает инфологической модели и целостности данных. С точки зрения инфологической модели эти две базы данных эквивалентны.

Зачем всё это надо

Возникает резонный вопрос - а зачем? Действительно, вводить в таблицы какие-то поля, что-то заменять, зачем? Итак, что мы получаем, проделав эту "механическую" операцию.

Упрощение сопровождения

Это область, где СК демонстрируют наибольшие преимущества. Поскольку операции связи между таблицами отделены от логики "внутри таблиц" - и то и другое можно менять независимо и не затрагивая остального.

Hапример - выяснилось, что города имеют дублирующиеся названия. Решено ввести в City еще одно поле - Регион (Region) и сделать ПК (City, Region). В случае ЕК - изменяется таблица City, изменяется таблица People - добавляется поле Region (да, да, для всех записей, про размеры молчу), переписываются все запросы, в том числе на клиентах, в которых участвует City, в них добавляются строка AND XXX.Region = City.Region.

Да, чуть не забыл, большинство серверов сильно не любят ALTER TABLE на поля, входящие в PRIMARY KEY и FOREIGN KEY.

В случае СК - добавляется поле в City, изменяется UNIQUE CONSTRAINT. Всё.

Еще пример - в случае СК изменение списка полей в SELECT никогда не заставляет переписывать JOIN. В случае ЕК - добавилось поле, не входящее в ПК связанной таблицы - переписывайте.

Еще пример - поменялся тип данных поля, входящего в ЕК. И опять переделки кучи таблиц, заново оптимизация индексов...

В условиях меняющегося законодательства это достоинство СК само по себе достаточно для их использования.

Уменьшение размера БД

Предположим в нашем примере, что средняя длина названия города - 10 байт. Тогда на каждого человека в среднем будет приходиться 10 байт для хранения ссылки на город (реально несколько больше за счёт служебной информации на VARCHAR и гораздо больше за счёт индекса по People.City, который придётся построить, чтобы REFERENCES работала эффективно). В случае СК - 4 байта. Экономия - минимум 6 байт на человека, приблизительно 10 Мб для г. Hовосибирска. Очевидно, что в большинстве случаев уменьшение размера БД - не самоцель, но это, очевидно, приведет и к росту быстродействия.

Звучали аргументы, что БД может сама оптимизировать хранение ЕК, подставив вместо него в People некую хэш-функцию (фактически создав СК сама). Hо ни один из реально существующих коммерческих серверов БД так не делает, и есть основания полагать, что и не будет делать. Простейшим обоснованием такого мнения является то, что при подобной подстановке банальные операторы ADD CONSTRAINT … FOREIGN KEY или DROP CONSTRAINT … FOREIGN KEY будут приводить к нешуточной перетряске таблиц, с ощутимым изменением всей БД (надо будет физически добавить или удалить (с заменой на хэш-функцию)) все поля, входящие в CONSTRAINT.

Увеличение скорости выборки данных

Вопрос достаточно спорный, однако, исходя из предположений, что:

  • База данных нормализована;
  • Записей в таблицах много (десятки тысяч и более);

Запросы преимущественно возвращают ограниченные наборы данных (максимум единицы процентов от размера таблицы).

быстродействие системы на СК будет ощутимо выше. И вот почему:

ЕК могут потенциально дать более высокое быстродействие, когда:

  • Требуется только информация, входящая в первичные ключи связанных таблиц;
  • нет условий WHERE по полям связанных таблиц.

Следующая страница (2/2) Следующая страница
 
 

 

Page generation 0.071 seconds