структура данных базы данных с использованием степеней двух - PullRequest
3 голосов
/ 18 февраля 2011

Я проектирую структуру данных и хотел знать, что я что-то упускаю, делая это таким образом.

Допустим, у меня есть столбец DAY типа int.

1  : Monday
2  : Tuesday
4  : Wednesday
8  : Thursday
16 : Friday
32 : Saturday
64 : Sunday

Если бы я хотел сохранить понедельник и пятницу, я бы ввел 17 в столбец ДЕНЬ.Если бы я хотел сохранить вторник и среду, я бы набрал 6 и т. Д.

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

Как называется эта концепция?

Ответы [ 3 ]

3 голосов
/ 18 февраля 2011

Некоторые люди могут сказать вам, что это «запах» кода, потому что он представляет денормализацию, но я думаю, что это совершенно правильное использование поля битовой маски:

-- Contains Saturday and any other combination of days
SELECT * FROM Table
WHERE (DayBitColumn & 32) = 32

-- Contains Saturday and any other combination of days, except Wednesday
SELECT * FROM Table
WHERE (DayBitColumn & 32) = 32 AND (DayBitColumn & 4) = 0

РЕДАКТИРОВАТЬ: как отметил @Andriy M, это можно записать более кратко как:

SELECT * FROM Table
WHERE (DayBitColumn & 36) = 32

['&' является побитовым И]

2 голосов
/ 18 февраля 2011

Суть вопроса ко мне:

Возможно ли это?
Будет ли это быстро?

Да, это возможно.
Даи нет - это зависит от вашего распределения данных.

Если вы сохранили их в битовых полях, SQL Server по-прежнему будет внутренне хранить их в одном байте, что означает, что вы получаете всю полезность хранилища, плюс не нужно вручную выполнить битовую маскировку. Зачем дублировать усилия?

Если вы храните их отдельно или в виде одного поля, индексация не поможет.

  • какотдельные поля: битовые маски обладают ужасной избирательностью, поскольку в качестве единственного поля есть только два ключа
  • : вы не можете индексировать бит в поле, даже если это возможно, это приводит к приведенной выше точке

Если вы, однако, нормализуете его и сохраняете его во вторичной таблице, скажем, Event_Day что-то вроде

EventID | Day
1         2
1         4

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

1 голос
/ 18 февраля 2011

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

2) Это быстро? В ограниченных случаях. WHERE skip = 0? Быстро. WHERE skip & 4 = 4 ... хорошо, в будущем у меня будет сканирование таблицы со всеми значениями, которые запрашиваются и обрабатываются для выполнения моего запроса.

Быстрая вставка, быстрая выборка числовых диапазонов, но очень медленная, если вы хотите знать все, для чего установлен флаг понедельника. Скорее, если вы хотите знать все, для чего установлен флаг воскресенья, и знать, что нужно запрашивать >= 64.

В ответе Майка Уитя есть правильные запросы для других ваших вопросов, поэтому я не буду дублировать это. Обратите внимание, что им потребуется сканирование таблицы, и она не будет быстрой. Если у вас есть их как отдельные столбцы, и вы будете индексировать каждый из этих столбцов, вы будете использовать много места для создания индексов. Вы увидите ограниченную выгоду от этого в таблице, если только они не охватывают индексы ... Суббота + что угодно, кроме среды, все равно придется сканировать либо всю субботу, либо всю среду в конфигурации дня на столбец. Сканирование всех этих таблиц в этом сценарии может оказаться быстрее, чем поиск, в зависимости от разброса данных и т. Д.

...