Тип данных для хранения массива флагов (битовая карта / битовый массив)


15

Мне нужно хранить битовый массив для каждой записи таблицы, поддерживая следующие операции:

  • Тестирование, если бит установлен, и установка бит (с использованием SQL)

  • Запрос и установка значения с помощью ADO 2.8 (не ADO.NET)

  • Индексирование (для того, чтобы воспользоваться функцией «индекс покрытия»)

Максимальное количество битов, которые должны храниться в этом массиве, является фиксированным, но может превышать 32 . То есть простой столбец int не всегда работает.

Из того, что я видел до сих пор, мои варианты:

  1. Используйте несколько столбцов int
  2. Использовать bigint (работает до тех пор, пока число битов <= 64)
  3. Используйте бинарный
  4. ?

Первый вариант будет работать, но потребуется немало рефакторинга в коде, который обращается к данным. Второй вариант - только временное облегчение, и из моих поисков пока я не слишком уверен, хорошо ли работает ADO с bigint . У меня нет опыта работы с двоичным файлом , и я не знаю других вариантов.

Какой тип данных вы бы выбрали, учитывая требования?

Ответы:


12

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

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

Если вы проверите один бит, это нормально. Если вы проверяете более одного бита, производительность очень быстро падает.

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

Многобитные проверки приводят к сканированию диапазона или индекса с функцией, выполняющейся для каждой строки. Это беспорядок.

Мой обходной путь был прост - я создал таблицу для хранения PK для каждого из проверяемых условий. Это изначально нелогично, но необходимое место мало (вы храните только PK), и поиск выполняется молниеносно, особенно если вы используете a UNIQUE CLUSTERED INDEX.

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

Индексация проста, поскольку вы просто индексируете все таблицы поиска по отдельности, и поскольку ваш кластеризованный ключ одинаков в основной таблице, и при поиске все ваши оценки merge joinочень эффективны.


1
Не могли бы вы подробнее рассказать о вашем обходном пути? Я нашел это, потому что я пытаюсь решить ту же самую основную проблему, но не уверен, как лучше сделать это.
Джошуа Франк

4

Если все, что вам нужно сохранить, это умеренное количество значений true / false, вы можете использовать bitтип данных.

Внутренне SQL Server хранит bitстолбцы, упакованные в байтовые «куски». Таким образом, до 8 bitстолбцов в вашей таблице SQL сохраняет это как упакованный 1 байт; 9-16 bitстолбцов в 2 байта и так далее.

Не похоже, что вы приближаетесь к пределу столбца, так что это кажется довольно простым. И, конечно же, их точное разделение позволяет вам назвать столбцы для удобства чтения и получить все возможности индексации, которые вы обычно делаете (если флаги очень избирательны, отфильтрованные индексы могут быть полезны, если вы можете ориентироваться на 2008+).

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.