Должен ли я индексировать бит в SQL Server?

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

Итак, что, если у меня есть таблица со 100 миллионами строк в ней, и я выбираю записи, где поле бит равно 1? И пусть говорят, что в любой момент времени есть только несколько записей, где бит-бит равен 1 (в отличие от 0). Стоит ли индексировать это поле бит или нет? Почему?

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

Ответ 1

Рассмотрим, что такое индекс в SQL - и индекс действительно представляет собой кусок памяти, указывающий на другие куски памяти (т.е. указатели на строки). Индекс разбит на страницы, чтобы части индекса могли быть загружены и выгружены из памяти в зависимости от использования.

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

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

Когда вы индексируете целочисленный столбец, индекс SQL содержит набор строк для каждого значения индекса. Если у вас есть диапазон от 1 до 10, у вас будет 10 указателей индекса. В зависимости от того, сколько строк есть, это можно по-разному выставить. Если ваш запрос ищет индекс, соответствующий "1", а затем где "Имя" содержит "Fred" (при условии, что столбец "Имя" не индексируется), SQL получает набор строк, соответствующих "1", очень быстро, а затем сканирование таблицы, чтобы найти остальное.

Итак, что действительно делает SQL, это попытка сократить рабочий набор (количество строк), который он должен перебрать.

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

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

Ответ 2

Я только что наткнулся на этот вопрос другим. Предполагая, что ваше утверждение о том, что только небольшая часть записей принимает значение 1 (и что это те, которые вам интересны), тогда фильтр-фильтр может быть хорошим выбором. Что-то вроде:

create index [IX_foobar] on dbo.Foobar (FooID) where yourBitColumn = 1

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

Ответ 3

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

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

Ответ 4

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

Простым примером может быть индекс ACTIVE, LASTNAME, а не просто имя, когда ваше приложение почти всегда ищет активных клиентов.

Ответ 5

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

http://statisticsio.com/Home/tabid/36/articleType/ArticleView/articleId/302/Never-Index-a-BIT.aspx

Изменить: новое местоположение статьи - http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit

Машина обратного пути для ранее "новой" позиции статьи: http://web.archive.org/web/20120201122503/http://sqlserverpedia.com/blog/sql-server-bloggers/never-index-a-bit/

Новое место размещения в SQL Server Pedia - Toadworld, в котором есть новая статья Кеннета Фишера, в которой обсуждаются следующие темы:

http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an-index-on-a-bit-column-will-never-be-used.aspx

Ответ 6

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

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

Ответ 7

Как говорили другие, вы захотите измерить это. Я не помню, где я это читал, но колонка должна иметь очень высокую мощность (около 95%), чтобы индекс был эффективным. Лучшим критерием для этого было бы создание индекса и проверка планов выполнения для значений 0 и 1 поля BIT. Если вы видите операцию поиска индекса в плане выполнения, то вы знаете, что ваш индекс будет использоваться.

Ваш лучший способ действий состоял бы в тестировании с помощью базовой таблицы SELECT * FROM WHERE BitField = 1; запросить и постепенно наращивать функциональность оттуда, пока вы не получите реалистичный запрос для своего приложения, изучив план выполнения с каждым шагом, чтобы убедиться, что поиск индекса все еще используется. По общему признанию, нет гарантии, что этот план выполнения будет использоваться в производстве, но есть хорошие шансы, что он будет.

Некоторая информация может быть найдена на sql-server-performance.com форумах и в ссылочной article

Ответ 8

"Я помню, что в какой-то момент я читал, что индексирование поля с низкой мощностью (небольшое количество различных значений) действительно не стоит делать"

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

Ответ 9

Если ваша цель состоит в том, чтобы запрашивать записи, где значение битового поля равно "1", вы можете попробовать индексированное представление вашей базовой таблицы, которое содержит только записи, где ваше поле бит равно "1". В корпоративной версии, если запрос может использовать индексированный вид вместо указанной таблицы для повышения производительности запроса, он будет использовать представление. Теоретически это увеличило бы скорость выбора запросов, которые будут искать только записи с битовым значением поля '1'.

http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx

Все это предполагает, что вы являетесь Microsoft SQL Server 2005 Enterprise. То же самое можно применить и к 2008 году, я не знаком с этой версией.

Ответ 10

Если ваше распределение довольно известно и не сбалансировано, например, 99% строк - бит = 1, а 1% - бит = 0, когда вы выполняете предложение WHERE с бит = 1, полное сканирование таблицы будет вокруг в то же время, что и сканирование индекса. Если вы хотите иметь быстрый запрос, в котором бит = 0, лучшим способом, который я знаю, является создание отфильтрованного индекса, добавление предложения WHERE bit = 0. Таким образом, этот индекс будет хранить только 1% строку. Затем выполнение WHERE бит = 0 просто позволит оптимизатору запросов выбрать этот индекс, а все строки из него будут бит = 0. У вас также есть преимущество в том, что требуется очень небольшое количество дискового пространства, чтобы сравнить полный индекс на бит.

Ответ 11

Если вы хотите узнать, есть ли у индекса нужные эффекты: проверить и снова проверить.

В целом вам не нужен индекс, который не сужает ваш стол из-за стоимости поддержки индекса. (стоимость > прибыль). Но если индекс в вашем случае сократит таблицу пополам, вы можете получить что-то, но поместить его на стол. Все зависит от точного размера/структуры вашей таблицы и того, как вы ее используете (количество операций чтения/записи).

Ответ 12

Вы не можете индексировать бит в SQL Server 2000, как это было указано в онлайн-книгах:

бит

Integer тип данных 1, 0 или NULL.

Примечания

Столбцы типа бит не могут имеют индексы на них.

Да, если у вас есть только несколько строк, из миллионов, поможет индекс. Но если вы хотите сделать это, в этом случае вам нужно сделать столбец a tinyint.

Примечание: Enterprise Manager не позволит вам создать индекс в столбце бит. Если вы хотите, вы можете вручную создать индекс в столбце бит:

CREATE INDEX IX_Users_IsActiveUsername ON Users
(
   IsActive,
   Username
)

Но SQL Server 2000 фактически не будет использовать такой индекс - запуск запроса, где индекс будет идеальным кандидатом, например:

SELECT TOP 1 Username 
FROM Users
WHERE IsActive = 0

SQL Server 2000 будет выполнять сканирование таблицы, действуя так, как будто индекс даже не существует. Если вы измените столбец на tinyint, SQL Server 2000 сделает поиск индекса. Кроме того, следующий непокрытый запрос:

SELECT TOP 1 * 
FROM Users
WHERE IsActive = 0

Он выполнит поиск индекса, а затем поиск по закладкам.


SQL Server 2005 имеет ограниченную поддержку индексов в столбцах бит. Например:

SELECT TOP 1 Username 
FROM Users
WHERE IsActive = 0

приведет к поиску индекса через индекс покрытия. Но незакрытый случай:

SELECT TOP 1 * 
FROM Users
WHERE IsActive = 0

не вызовет поиск индекса, а затем поиск по закладке, он выполнит сканирование таблицы (или кластерное сканирование индекса), вместо того, чтобы выполнять поиск индекса, а затем поиск по закладкам.

Проверено экспериментами и прямым наблюдением.

Ответ 13

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

Ответ 15

измерить время отклика до и после и посмотреть, стоит ли это; теоретически это должно улучшить производительность для запросов с использованием индексированных полей, но это действительно зависит от распределения значений true/false и других полей, связанных с запросами, которые вы беспокоитесь о

Ответ 16

Это общий запрос? Это может стоить того, когда вы ищете "горстку" записей, но не сильно поможет вам в других строках. Существуют ли другие способы идентификации данных?

Ответ 17

Единственным фактором является кардинальность, а другая - насколько хорошо индекс делится вашими данными. Если у вас около половины с половиной 0 с, то это поможет. (Предполагая, что этот индекс является лучшим путем выбора, чем какой-либо другой индекс). Однако как часто вы вставляете и обновляете? Добавление индексов для производительности SELECT также ухудшает производительность INSERT, UPDATE и DELETE, поэтому имейте это в виду.

Я бы сказал, если 1s до 0s (или наоборот) не лучше 75% -25%, не беспокойтесь.

Ответ 18

Ян Бойд прав, когда говорит, что вы не можете сделать это через Enterprise Manager для SQL 2000 (см. его заметку о создании его через T-SQL.

Ответ 19

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