Правильное использование таблиц поиска

25

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

Допустим, у меня есть таблица с именем Employees:

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Представьте на мгновение, что данные более сложные и содержат сотни строк. Самая очевидная вещь, которую я вижу, которую можно переместить в таблицу поиска, - это Position. Я мог бы создать таблицу с именем Positions и вставить внешние ключи из таблицы Positions в таблицу Employees в столбце Position.

ID  Position
1   Manager
2   Sales

Но как далеко я могу продолжать разбивать информацию на меньшие таблицы поиска, прежде чем она станет неуправляемой? Я мог бы создать таблицу Гендер и иметь 1 соответствует мужскому и 2 соответствуют женскому в отдельной таблице поиска. Я мог бы даже поместить LNames и FNames в таблицы. Все записи «Джон» заменяются внешним ключом 1, который указывает на таблицу FName, в которой говорится, что идентификатор 1 соответствует Джону. Если вы зайдете в эту кроличью нору слишком далеко, как показано ниже, ваша таблица сотрудников будет превращена в беспорядок внешних ключей:

ID  LName   FName   Gender  Position
1   1       1       1       1
2   1       2       2       2
3   2       1       1       2

Хотя это может или не может быть более эффективным для обработки сервером, это, конечно, нечитаемо для обычного человека, который может пытаться поддерживать его, и усложняет для разработчика приложения, пытающегося получить к нему доступ. Итак, мой реальный вопрос: как далеко это слишком далеко? Есть ли «лучшие практики» для такого рода вещей или хороший набор руководящих принципов? Я не могу найти какую-либо информацию в Интернете, которая бы действительно привела к хорошему, полезному набору рекомендаций для этой конкретной проблемы, с которой я столкнулся. Дизайн базы данных для меня старая шляпа, но ХОРОШИЙ дизайн базы данных очень новый, поэтому слишком технические ответы могут быть у меня над головой. Любая помощь будет оценена!

Брэд Тернер
источник
5
Использование таблиц поиска - это одно. Замена текста на идентификаторы - это совсем другое.
Майк Шеррилл 'Cat Recall'
1
Пол не всегда может быть установлен на 2 значения! Теперь, когда у нас есть гендерные переходы, то есть заявителю, возможно, не нужны дополнительные категории, такие как «рожденный мужчина сейчас женщина» или «рожденный женщина сейчас мужчина».
@ Майк, хороший комментарий!
Уолтер Митти
В моем магазине мыслители смогли остановиться после того, как только четыре варианта, мужской, женский и транссексуальный, не раскрылись.
Кевинский

Ответы:

22

Но как далеко я могу продолжать разбивать информацию на меньшие таблицы поиска, прежде чем она станет неуправляемой? Я мог бы создать таблицу Гендер и иметь 1 соответствует мужскому и 2 соответствуют женскому в отдельной таблице поиска.

Вы смешиваете две разные проблемы. Одной из проблем является использование таблицы поиска; другое - использование суррогатных ключей (идентификационных номеров).

Начните с этой таблицы.

ID  LName   FName   Gender  Position
1   Doe     John    Male    Manager
2   Doe     Jane    Female  Sales
3   Smith   John    Male    Sales

Вы можете создать таблицу поиска для таких позиций.

create table positions (
  pos_name varchar(10) primary key
);

insert into positions
select distinct position 
from employees;

alter table employees
add constraint emp_fk1
foreign key (position) 
  references positions (pos_name);

Ваша исходная таблица выглядит точно так же, как и до создания таблицы поиска. И таблица сотрудников требует не дополнительная оплата не включается , чтобы получить полезные и читаемые данные из него.

Использование таблицы поиска сводится к следующему: требуется ли вашему приложению контроль над входными значениями, которые предоставляет ссылка на внешний ключ? Если это так, то вы всегда можете использовать таблицу поиска. (Независимо от того, использует ли он суррогатный ключ.)

В некоторых случаях вы сможете полностью заполнить эту таблицу во время разработки. В других случаях пользователи должны иметь возможность добавлять строки в эту таблицу во время выполнения. (И вам, вероятно, потребуется включить некоторые административные процессы для просмотра новых данных.) Пол, который на самом деле имеет стандарт ISO , может быть полностью заполнен во время разработки. Названия улиц для международных онлайн-заказов на товары, вероятно, должны быть добавлены во время выполнения.

Майк Шеррилл 'Cat Recall'
источник
2
Я не знал, что ты мог сделать все это! То, как работает ваш метод, прекрасно. Спасибо!
Брэд Тернер
4
Я присоединился к DBA Stack Exchange, чтобы проголосовать за этот ответ. Это красиво и никогда не приходило мне в голову. Благодарность!
CindyH
Я ценю метод заполнения таблицы поиска. Моя причина для прочтения этого вопроса состояла в том, чтобы увидеть, будет ли польза, которую я не мог видеть суррогатным ключом в моих таблицах поиска. Вы подтвердили, что одно текстовое поле так же хорошо и полезно, как кажется. Спасибо.
Синтия V
8

В вашей таблице «Сотрудники» я буду искать только «Позиция», потому что это ограниченный набор данных, которые можно расширять.

  • Пол является самоописываемым (скажем, Mили F), ограниченным 2 значениями, и может быть применен с ограничением CHECK. Вы не будете добавлять новые гендеры (игнорируя политическую корректность)
  • Имя «Джон» не является частью ограниченного, ограниченного набора данных: потенциальный набор данных огромен до практически безграничного, поэтому он не должен быть поиском

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

Кроме того, если у вас есть миллион сотрудников, эффективнее хранить tinyint PositionID, чем varchar.

Давайте добавим новый столбец «зарплата валюта». Я бы использовал таблицу поиска с ключом CHF, GBP, EUR, USD и т. Д. Я бы не использовал суррогатный ключ. Это может быть ограничено ограничением CHECK, например, Gender, но это ограниченный, но расширяемый набор данных, например Position. Я привел этот пример, потому что я использовал бы естественный ключ, даже если он появляется в миллионах строк данных о сотрудниках, несмотря на то, что он char (3), а не tinyint

Итак, чтобы подвести итог, вы используете таблицы поиска

  1. где у вас есть конечный, но расширяемый набор данных в столбце
  2. где не самоописание
  3. чтобы избежать аномалий изменения данных
ГБН
источник
1
Одной из возможных причин поместить пол в таблицу поиска является локализация.
a_horse_with_no_name
1
«Гендер ... (скажем, M или F), ограниченный двумя значениями ... игнорируя политическую корректность» - по иронии судьбы, именно та политическая корректность, которую вы, похоже, ненавидите, заставляет людей ошибочно «гендерить» (' «Мужской», «Женский»), когда они означают «секс» («Мужской», «Женский»). Если контекст имеет грамматический пол, то обычно существует более двух значений. Если в контекст записывается пол новорожденного, то существует как минимум четыре значения («официально не оценивалось» и «официальное оценивание было неубедительным»). ps Я не хочу звучать резко, я наслаждался иронией :)
onedaywhen
4
@onedaywhen: правильное значение для столбца под названием «Секс» - «Да, пожалуйста». Если вы не британец
gbn
Термин «аномалии» используется здесь неправильно, поскольку этот термин имеет другое конкретное значение, связанное с нормализацией, и ссылка неуместна.
Philipxy
5

Ответ "это зависит". Не очень удовлетворительно, но есть много влияющих на дизайн. Если у вас есть программисты приложений, проектирующие базу данных, то структура, подобная описанной вами, работает для них, потому что ORM скрывает сложность. Вы будете выдергивать волосы, когда будете писать отчеты, и вам придется объединить десять таблиц, чтобы получить адрес.

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

Чтобы повторно использовать любимую цитату

«Один мудрец однажды сказал мне:« Нормализуй, пока не болит, денормализуй, пока не заработает ».

Где-то там есть сладкое место. Мой опыт показывает, что наличие ключевого идентификатора в нескольких таблицах не является таким серьезным преступлением, как некоторые думают, если вы никогда не измените первичные ключи.

Возьмите этот сокращенный пример сильно нормализованных таблиц из реальной системы.

CREATE TABLE PROPERTY
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_TYPE
(ID                          NUMBER(9)           NOT NULL);

CREATE TABLE PROPERTY_LOCALE 
PROPERTY_ID                  NUMBER(9)           NOT NULL,
(LOCALE_ID                   NUMBER(9)           NOT NULL,  --language 
VALUE                        VARCHAR2(200)       NOT NULL);

CREATE TABLE PROPERTY_DEPENDENCY
(PROPERTY_ID                 NUMBER(9)           NOT NULL,
 PARENT_PROPERTY_ID          NUMBER(9)                   ,
 PROPERTY_TYPE_ID            NUMBER(9)           NOT NULL);

Эти таблицы устанавливают связанный список отдельных свойств и родительских дочерних свойств, и они используются здесь

  CREATE TABLE CASE_PROPERTY
  (ID                        NUMBER(9)           NOT NULL,
  PARENT_ID                  NUMBER(9),
  CASE_ID                    NUMBER(9)           NOT NULL,
  PROPERTY_ID                NUMBER(9),
  PROPERTY_TYPE_ID           NUMBER(9)           NOT NULL);

Это выглядит хорошо: получить все случаи с помощью property_id в один выбор

Давайте возьмем список для выбора

 Select pl.value, pd.property_id
 from property_locale pl, property_dependency pd
 where pl.property_id = pd.property_id
 and pd.property_type_id = 2;  --example number

Теперь попробуйте выбрать все свойства случая, если он имеет property_types 3 и 4 и 5, или нет ...

SELECT   cp2.case_id,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 2
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE1,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 34
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE2,
         (SELECT   pl.VALUE
            FROM   case_property cp, property_locale pl
           WHERE       cp.property_id = pl.property_id
                   AND CP.PROPERTY_TYPE_ID = 4
                   AND pl.locale_id = 2
                   AND cp.case_id = cp2.case_id)
            AS VALUE3
  FROM   case_property cp2
 WHERE   cp2.case_id = 10293  

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

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

kevinsky
источник
5
Идентификационные номера не имеют ничего общего с нормализацией. Тот факт, что каждая таблица имеет идентификационный номер, не означает, что она указана в 5NF или даже в 3NF. Это просто означает, что вам нужно сделать много соединений, чтобы получить полезные данные из этой таблицы.
Майк Шеррилл 'Cat Recall'