Индекс для нескольких битовых полей в SQL Server - PullRequest
6 голосов
/ 19 августа 2011

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

Данная таблица является транзакционной таблицей, которая может иметь десятки миллионов строк, и производительность как вставки, так и выбора достаточно критична. Хотя в настоящее время мы не совсем уверены в распределении данных, комбинация всех флагов должна обеспечить относительно хорошую мощность, то есть сделать «стоящий» индекс для использования SQL Server.

Типичными сценариями запроса выбора могут быть выбор записей на основе только 3 или 4 флагов, например, WHERE FLAG3=1 AND FLAG7=0 AND FLAG9=1. Было бы непрактично создавать отдельные индексы для всех комбинаций флагов, используемых этими запросами выбора, поскольку их будет много.

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

На данный момент мы рассматриваем два основных варианта:

  • Создайте один индекс, который включает все битовые поля (это, вероятно, будет включать 1 или 2 других int поля, которые будут всегда использоваться). Меня беспокоит то, что, учитывая типичное использование только нескольких полей, этот подход пропускает индекс и прибегает к сканированию таблицы. Давайте назовем это Вариант A (Прочитав некоторые ответы, кажется, что этот подход не будет работать хорошо, так как порядок полей в индексе будет иметь значение, что делает невозможным эффективную индексацию по ALL поля).
  • Эффективно делайте то, что, как я считаю, SQL Server делает внутренне, и кодируйте битовые поля в одно целое поле, используя двоичные операторы (И-номера и ИЛИ-номера вместе: 1, 2, 4, 8 и т. Д.). Меня беспокоит то, что нам нужно выполнить какой-то расчет для запроса этого закодированного поля, что снова пропустит индекс. Техническое обслуживание и сложность этого решения также является проблемой. Давайте назовем это Вариант B . Дополнительная информация: Аргумент для этого подхода состоит в том, что у нас может быть относительно простой и короткий индекс, который включает одно или два других поля из таблицы и этого поля. Другие поля сузили бы количество записей, которые необходимо оценить, и, поскольку закодированное поле будет содержать все наши битовые поля, SQL Server сможет выполнять вычисления, используя данные, извлеченные непосредственно из индекса (т. Е. Сканирование индекса). ), в отличие от таблицы (т. е. сканирование таблицы).

В данный момент мы сильно склоняемся к Вариант B . Для полноты картины это будет работать на SQL Server 2008.

Любой совет будет принят с благодарностью.

Редактировать: орфография, ясность, пример запроса, дополнительная информация о Опция B .

Ответы [ 3 ]

6 голосов
/ 19 августа 2011

Один столбец BIT, как правило, недостаточно избирателен, чтобы его можно было рассматривать даже для использования в индексе. Таким образом, индекс для одного столбца BIT на самом деле не имеет смысла - в среднем вам всегда придется искать около половины записей в таблице (селективность 50%), и поэтому оптимизатор запросов SQL Server вместо этого будет использовать сканирование таблицы. .

Если вы создадите один индекс для всех 15 bit столбцов, у вас не возникнет этой проблемы - поскольку у вас есть 15 вариантов да / нет, ваш индекс станет довольно избирательным.

Проблема в том, что последовательность битовых столбцов важна. Ваш индекс будет только когда-либо , если ваш SQL-оператор использует хотя бы 1-n из самых левых BIT столбцов.

Так что, если ваш индекс включен

Col1,Col2,Col3,....,Col14,Col15

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

  • Col1
  • Col1 и Col2
  • Col1 и Col2 и Col3 ....

и так далее. Но его нельзя использовать для запроса, который задает Col6,Col9 и Col14.

Из-за этого я не думаю, что индекс вашей коллекции из BIT столбцов действительно имеет большой смысл.

Являются ли эти 15 BIT столбцы единственными столбцами, которые вы используете для запросов? Если нет, я бы попытался объединить те столбцы BIT, которые вы используете чаще всего для выбора, с другими столбцами, например, иметь индекс на Name и Col7 или что-то еще (тогда ваши столбцы BIT могут добавить дополнительную селективность к другому индексу)

3 голосов
/ 19 августа 2011

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

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

  1. Таблица поиска имен этих битовых флагов.например, CREATE TABLE Flags (id int IDENTITY(1,1), Name varchar(256)) (вам не нужно делать id столбцом идентификатора, если вы хотите вручную управлять идентификаторами - например, 2,4,8,16,32,64,128 как двоичные флаги.)
  2. Создайте новую таблицу ссылок , которая содержит идентификаторы исходной таблицы данных и новую таблицу ссылок, например, CREATE TABLE DataFlags_Link (id int IDENTITY(1,1), MyFlagId int, DataId int)

Затем можно создать индекс для DataFlags_LinkЗапросы к таблицам и записи наподобие:

SELECT Data.*
FROM Data
INNER JOIN DataFlags_Link ON Data.id = DataFlags_Link.DataId
WHERE DataFlags_Link.MyFlagId IN (4,7,2,8)

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

Производительность и обслуживание идут рука об руку с базами данных.Вы не можете иметь одно без другого.

1 голос
/ 22 августа 2011

Хотя я думаю, что ответ Нила Фенвика, вероятно, правильный, я думаю, что реальный ответ заключается в том, чтобы опробовать различные варианты и посмотреть, какой из них достаточно быстрый.

Вариант 1, вероятно, является наиболее простым решением, и поэтомувероятно, наиболее поддерживаемый - и вполне может быть достаточно быстрым.

Я бы создал базу данных прототипа со схемой "option 1" и использовал бы что-то вроде http://www.red -gate.com / products/ sql-development / sql-data-generator / или http://sourceforge.net/projects/dbmonster/, чтобы создать вдвое больше данных, чем вы ожидаете, а затем построить запросы, которые вам нужны.Согласитесь с приемлемым временем отклика и рассмотрите «более быструю» схему, только если вы превысили это время отклика (и вы не можете бросить аппаратное обеспечение при проблеме).

Решение Нейла, вероятно, столь же очевидно и обслуживаемо, как и «вариант 1», и его должно быть легко проиндексировать.Тем не менее, я бы все же протестировал его, создав схему-прототип и сгенерировав много тестовых данных ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...