2010-05-24 6 views
2

Является ли разумным хранить массивы в столбцах таблицы? Точнее, я имею в виду следующую схему, которая к моему пониманию нарушающего нормализации:Массивы в таблицах базы данных и нормализации


create table Permissions(
    GroupID int not null default(-1), 
    CategoryID int not null default(-1), 
    Permissions varchar(max) not null default(''), 
    constraint PK_GroupCategory primary key clustered(GroupID,CategoryID) 
); 

и это:


create table Permissions(
    GroupID int not null default(-1), 
    CategoryID int not null default(-1), 
    PermissionID int not null default(-1), 
    constraint PK_GroupCategory primary key clustered(GroupID,CategoryID) 
); 

UPD3: Я предвижу разрешения в виде строки с разделителями запятыми, поскольку MSSQL является нашим основным цели развертывания.

UPD: Забыло упомянуть, в рамках этого конкретного вопроса мы рассмотрим, что «выборку строк, которые имеют разрешения X» не будет выполнено, а все поиски будут сделаны GroupID и CategoryID только

UPD2: Я представляю типичный сценарий использования следующим образом:


int category_id=42; 
int[] array_of_groups=new int[]{40,2,42}; 
if(!Permissions.Check(category_id, array_of_groups, Permission.EatAndDrink)) { 
    throw new StarveToDeathException(); 
} 

Тхо ughts?

Заранее благодарен!

ответ

0

Проблема с первой реализацией заключается в том, что на самом деле она не использует массив, а представляет собой конкатенированную строку.

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

Если вы использовали базу данных, поддерживающую изначально массивы, как атомное значение PostgreSQL, тогда аргумент будет другим.

Основываясь на втором требовании предлагаемого запроса, я должен предложить, чтобы второй был лучшим, поскольку вы можете просто запросить SELECT count(*) FROM Permissions WHERE CategoryID = 42 AND GroupID IN (40, 2, 42) AND PermissionID = 2 (при условии, что EatAndDrink имеет идентификатор 2). Однако для первой версии потребуется получить все разрешения для каждой группы и разбор строки, прежде чем вы сможете проверить, включает ли она запрашиваемое разрешение.

+0

Забыл упомянуть, что в рамках данного конкретного вопроса мы будем считать, что «выборки строк, имеющих разрешение X», не будут выполняться, вместо этого все поисковые запросы будет производиться только с помощью GroupID и CategoryID. –

+1

Пока пока вас не попросят подготовить отчет обо всех пользователях, у которых в какой-то момент есть разрешение X. –

+0

Я почти уверен :) Однако «GroupID IN (40, 2, 42)» требует динамического SQL в MSSQL или что-то еще, что они предлагают на http://www.sommarskog.se/arrays-in-sql-2005.html. –

0

Ваш второй пример, вероятно, следует:

constraint PK_GroupCategory primary key clustered(GroupID,CategoryID,PermissionID) 

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

+0

Спасибо! Я обновил вопрос с использованием сценария использования –

+0

@ Иван Петров. Я бы сказал, что это необходимо нормализовать с помощью PermissionID (похоже, что только присутствие указывает GRANT, но обычно у вас может быть больше прав для объекта), как в схеме таблицы , В глубине души вы знаете, что это правильно. –

0

Это умный

Иногда это зависит. Я бы сказал, это зависит от того, насколько узко вы определяете нормализованные вещи.

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

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

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

+0

Я envision Разрешения как строка с разделителями-запятыми, поскольку MSSQL - наша основная цель развертывания - не поддерживает массивы, и на самом деле это мои большие личные дискуссии о том, нужно ли это, поэтому этот вопрос :) –

0

Если вы запрашиваете только GroupID и/или CategoryID, в этом нет ничего плохого. Нормализация будет означать больше таблиц, строк и объединений. Поэтому для больших баз данных это может отрицательно повлиять на производительность.

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

+0

Хорошая мысль, учитывая, что я хочу, чтобы они быть гибким, я не могу обеспечить целостность с помощью триггеров? Это похоже на слишком много хлопот для меня, хотя ... –

+0

Ну, используя строку, вы в основном решили, чтобы приложение полностью обрабатывало данные.Если вас беспокоит его целостность, я бы нормализовал данные и перешел со вторым решением (PermissionID вместо строки). –

1

я предлагаю взять нормализованную дорогу по следующим причинам:

  • Имея таблицу, содержащую все возможные разрешения, у вас есть самодокументированно данные. Вы можете добавить описание для каждого разрешения. Это определенно превосходит конкатенированные значения id без какого-либо смысла.
  • Вы получаете все преимущества ссылочной целостности и можете быть уверены, что в ваших данных нет фиктивных идентификаторов доступа.
  • Внесение и удаление разрешений будет проще - вы добавляете или удаляете записи. С помощью конкатенированной строки вы будете обновлять столбец и удалять запись только при удалении последнего разрешения.
  • Ваш дизайн будущий - вы говорите, что хотите только запросить идентификаторы CategoryID и GroupID, вы можете сделать это уже с нормализованными таблицами. Кроме того, вы также, например, сможете добавлять другие свойства к своим разрешениям, запросить по разрешению и т. Д.
  • Производительность -wise, я думаю, что на самом деле будет быстрее получить результирующий набор идентификаторов, для синтаксического анализа строки для целых чисел. Измерять с фактическими данными и их реализацией ...
+0

Это имеет смысл, большое спасибо за вход! –

Смежные вопросы