Я помню, как однажды прочитал, что индексирование поля с низкой мощностью (небольшим количеством различных значений) на самом деле не стоит делать. Признаюсь, я недостаточно знаю, как работают индексы, чтобы понять, почему это так.
Так что, если у меня есть таблица со 100 миллионами строк в ней, и я выбираю записи, в которых битовое поле равно 1? И предположим, что в любой момент времени существует только несколько записей, в которых битовое поле равно 1 (в отличие от 0). Стоит ли индексировать это битовое поле или нет? Зачем?
Конечно, я могу просто протестировать это и проверить план выполнения, и я сделаю это, но мне также интересно узнать о теории, лежащей в основе этого. Когда мощность имеет значение, а когда нет?
sql-server
indexing
Jeremcc
источник
источник
Ответы:
Рассмотрим, что такое индекс в SQL - и индекс на самом деле является фрагментом памяти, указывающим на другие фрагменты памяти (то есть указатели на строки). Индекс разбит на страницы, так что части индекса могут быть загружены и выгружены из памяти в зависимости от использования.
Когда вы запрашиваете набор строк, SQL использует индекс для поиска строк быстрее, чем сканирование таблицы (просматривая каждую строку).
В SQL есть кластерные и некластеризованные индексы. Насколько я понимаю, кластерные индексы заключаются в том, что они группируют похожие значения индекса на одной странице. Таким образом, когда вы запрашиваете все строки, соответствующие значению индекса, SQL может вернуть эти строки из кластеризованной страницы памяти. Вот почему попытка кластеризации индекса столбца GUID - плохая идея - вы не пытаетесь кластеризовать случайные значения.
Когда вы индексируете целочисленный столбец, индекс SQL содержит набор строк для каждого значения индекса. Если у вас есть диапазон от 1 до 10, у вас будет 10 указателей индекса. В зависимости от количества строк это может быть разбито на страницы по-разному. Если ваш запрос ищет индекс, соответствующий «1», а затем, где Name содержит «Fred» (при условии, что столбец Name не проиндексирован), SQL очень быстро получает набор строк, соответствующих «1», затем таблица просматривает, чтобы найти остальные.
Итак, что на самом деле SQL пытается уменьшить рабочий набор (количество строк), который он должен перебирать.
Когда вы индексируете битовое поле (или некоторый узкий диапазон), вы уменьшаете рабочий набор только на количество строк, соответствующих этому значению. Если у вас есть небольшое количество совпадающих строк, это сильно уменьшит ваш рабочий набор. Для большого количества строк с распределением 50/50 это может дать вам очень небольшой выигрыш в производительности по сравнению с поддержанием индекса в актуальном состоянии.
Причина, по которой все говорят о тестировании, заключается в том, что SQL содержит очень умный и сложный оптимизатор, который может игнорировать индекс, если решит, что сканирование таблицы выполняется быстрее, или может использовать сортировку, или может организовать страницы памяти, как это черт возьми, нравится.
источник
Я просто наткнулся на этот вопрос в качестве другого. Предполагая, что ваше утверждение о том, что только несколько записей принимают значение 1 (и что это те, которые вас интересуют), тогда отфильтрованный индекс может быть хорошим выбором. Что-то вроде:
Это создаст существенно меньший индекс, который оптимизатор достаточно умен, чтобы использовать, когда это предикат в вашем запросе.
источник
yourBitColumn = @value
, оптимизатор не сможет определить, можно ли использовать отфильтрованный индекс.100 миллионов записей, из которых только несколько имеют битовое поле, равное 1? Да, я бы подумал, что индексация битового поля определенно ускорит запрос записей с битом = 1. Вы должны получить логарифмическое время поиска из индекса, а затем коснуться только нескольких страниц с записями с битом = 1. В противном случае вам пришлось бы перебирать все страницы таблицы из 100 миллионов записей.
Опять же, я определенно не эксперт по базам данных и могу упустить что-то важное.
источник
Если ваше распределение хорошо известно и несбалансировано, например, 99% строк имеют бит = 1, а 1% - бит = 0, когда вы выполняете предложение WHERE с битом = 1, полное сканирование таблицы будет примерно в то же время, что и индексное сканирование. Если вы хотите получить быстрый запрос, где бит = 0, лучший способ, который я знаю, - это создать отфильтрованный индекс, добавив предложение WHERE bit = 0. Таким образом, этот индекс будет хранить только строку 1%. Затем установка WHERE bit = 0 просто позволит оптимизатору запросов выбрать этот индекс, и все строки из него будут иметь bit = 0. У вас также есть преимущество в том, что требуется очень небольшой объем дискового пространства для сравнения полного индекса на бите. .
источник
Хотя я не думаю, что я бы индексировал ТОЛЬКО битовый столбец сам по себе, очень часто включать битовые столбцы как часть составного индекса.
Простым примером может быть указатель на ACTIVE, LASTNAME, а не только на фамилию, когда ваше приложение почти всегда ищет активных клиентов.
источник
Если вы не читали, Джейсон Мэсси недавно написал статью, в которой обсуждалась именно эта тема.
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/
Новое местоположение 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
машина обратного пути: http://web.archive.org/web/20150508115802/http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2014/02/17/dba-myths-an -index-on-a-bit-column-никогда-не будет использоваться.aspx
источник
Конечно, стоит, особенно если вам нужно получить данные по этому значению. Это было бы похоже на использование разреженной матрицы вместо использования нормальной матрицы.
Теперь с SQL 2008 вы можете использовать функции секционирования и фильтровать данные, которые входят в индекс. Недостатком более ранних версий было бы то, что индекс создавался бы для всех данных, но это можно оптимизировать, сохранив интересующие значения в отдельной группе файлов.
источник
Как говорили другие, вам нужно это измерить. Я не помню, где я это читал, но столбец должен иметь очень высокую мощность (около 95%), чтобы индекс был эффективным. Лучшим тестом для этого будет создание индекса и проверка планов выполнения для значений 0 и 1 поля BIT. Если вы видите операцию поиска по индексу в плане выполнения, значит, вы знаете, что ваш индекс будет использоваться.
Лучше всего протестировать с помощью простой таблицы SELECT * FROM WHERE BitField = 1; query и постепенно наращивайте функциональность оттуда, шаг за шагом, пока у вас не будет реалистичного запроса для вашего приложения, проверяя план выполнения на каждом шаге, чтобы убедиться, что поиск по индексу все еще используется. По общему признанию, нет никакой гарантии, что этот план выполнения будет использован в производственной среде, но есть большая вероятность, что это будет.
Некоторую информацию можно найти на форумах sql-server-performance.com и в указанной статье
источник
«Я помню, как однажды прочитал, что индексировать поле с низкой мощностью (малое количество различных значений) на самом деле не стоит»
Это потому, что SQL Server почти всегда находит более эффективным просто сканирование таблицы, чем чтение индекса. Таким образом, ваш индекс никогда не будет использоваться, и поддерживать его - пустая трата времени. Как говорили другие, это может быть нормально в составном индексе.
источник
Если ваша цель - быстрее запрашивать записи, в которых значение битового поля равно «1», вы можете попробовать индексированное представление вашей базовой таблицы, которое содержит только записи, в которых битовое поле равно «1». В корпоративной версии, если запрос может использовать индексированное представление вместо указанной таблицы для повышения производительности запроса, он будет использовать представление. Теоретически это повысит скорость выборочных запросов, которые ищут только записи со значением битового поля «1».
http://www.microsoft.com/technet/prodtechnol/sql/2005/impprfiv.mspx
Все это предполагает, что вы используете Microsoft SQL Server 2005 Enterprise. То же самое может относиться к 2008 году, я не знаком с этой версией.
источник
Если вы хотите узнать, оказывает ли индекс желаемый эффект: протестируйте и проверьте еще раз.
В общем, вам не нужен индекс, который недостаточно сужает вашу таблицу из-за затрат на поддержание индекса. (стоимость> прибыль). Но если индекс в вашем случае сократит таблицу пополам, вы можете кое-что получить, кроме как положить это на стол. Все зависит от точного размера / структуры вашей таблицы и от того, как вы ее используете (количество операций чтения / записи).
источник
Само по себе нет, поскольку это приводит к очень низкой избирательности. В составе составного индекса. вполне возможно, но только после других столбцов равенства.
источник
Вы не можете индексировать битовое поле в SQL Server 2000, как было указано в электронной документации в то время:
Да, если у вас всего несколько строк из миллионов, индекс поможет. Но если вы хотите это сделать, вам нужно сделать столбец a
tinyint
.Примечание : Enterprise Manager не позволит вам создать индекс для битового столбца. Если вы хотите, вы все равно можете вручную создать индекс для битового столбца:
Но SQL Server 2000 на самом деле не будет использовать такой индекс - выполнение запроса, в котором индекс будет идеальным кандидатом, например:
Вместо этого SQL Server 2000 выполнит сканирование таблицы, действуя так, как будто индекса даже не существует. Если вы измените столбец на tinyint SQL Server 2000 воли делать поиск по индексу. Также следующий непокрытый запрос:
Он выполнит поиск по индексу, а затем по закладке.
SQL Server 2005 имеет ограниченную поддержку индексов по битовым столбцам. Например:
вызовет поиск по индексу покрытия. Но не покрытый случай:
не вызовет поиск по индексу с последующим поиском по закладкам, он будет выполнять сканирование таблицы (или сканирование кластерного индекса), а не выполнять поиск по индексу с последующим поиском по закладке.
Проверено экспериментально и прямым наблюдением.
источник
очень поздний ответ ...
Да, это может быть полезно по мнению команды SQL CAT (обновлено, консолидировано)
источник
Это общий вопрос? Это может стоить того при поиске "горстки" записей, но не поможет вам в других строках. Есть ли другие способы идентифицировать данные?
источник
Кардинальность - это один фактор, другой - насколько хорошо индекс разделяет ваши данные. Если у вас есть примерно половина единиц и половина нулей, это поможет. (Предполагая, что этот индекс - лучший путь для выбора, чем какой-либо другой индекс). Однако как часто вы вставляете и обновляете? Добавление индексов для производительности SELECT также ухудшает производительность INSERT, UPDATE и DELETE, так что имейте это в виду.
Я бы сказал, что если от 1 до 0 (или наоборот) не лучше, чем от 75% до 25%, не беспокойтесь.
источник
измерьте время отклика до и после и посмотрите, стоит ли оно того; теоретически это должно улучшить производительность запросов с использованием индексированных полей, но на самом деле это зависит от распределения истинных / ложных значений и других полей, участвующих в запросах, которые вас беспокоят.
источник
Иэн Бойд прав, когда говорит, что вы не можете сделать это с помощью Enterprise Manager for SQL 2000 (см. Его примечание относительно создания этого с помощью T-SQL.
источник
Здесь вам нужно быть умным, чтобы делать запросы, вы должны знать значение нагрузки в вашем столбце, если загрузка истины больше в вашей системе, и вы хотите проверить все истинные значения, напишите свой запрос, чтобы проверить, не ложно ли ... это поможет много , это всего лишь уловка.
источник