Каково влияние замены индексов на отфильтрованные (не нулевые значения) индексы?

10

Наш проект работает с очень большой, очень сложной базой данных. Примерно месяц назад мы заметили, что пространство, используемое индексированными столбцами, содержащими нулевые значения, становится слишком большим. В ответ на это я написал в виде сценария, который будет динамически выполнять поиск по всем одноколоночным индексам, содержащим более 1% нулевых значений, а затем отбрасывать и воссоздавать эти индексы как отфильтрованные индексы при условии, что значение равно NOT NULL. Это приведет к удалению и воссозданию сотен индексов по всей базе данных и, как правило, освобождает почти 15% пространства, используемого всей БД.

Теперь у меня есть два вопроса по этому поводу:

А) Каковы недостатки использования фильтрованных индексов таким способом? Я бы предположил, что это только улучшит производительность, но есть ли какие-либо риски производительности?

B) Мы получили ошибки ( «не могу удалить индекс XYZ, потому что он не существует или у вас нет разрешения» ) при удалении и повторном создании индексов, хотя при последующей проверке все прошло точно так, как ожидалось. Как это может случиться?

Спасибо за любую помощь!

Изменить: в ответ на @ Томас Кейсер

Привет и спасибо, но оказалось, что это была катастрофа. В то время мы не понимали несколько вещей, таких как:

  1. Во время запроса SQLOS создает планы индекса, прежде чем определить, что он не может использовать значения NULL для объединения столбцов таблицы. IE, вам действительно нужно иметь фильтр предложения WHERE, соответствующий индексу для каждого отфильтрованного индекса, используемого в запросе, иначе индекс не будет использоваться вообще.
  2. Удаление и создание индексов и избыточное обновление их статистики еще раз после этого может оказаться недостаточным для создания обновленных планов, как мы и предполагали. В некоторых случаях оказывается, что только достаточно высокая рабочая нагрузка заставит SQL Server пересмотреть планы.
  3. Есть некоторые экзотические черты в функциональности планировщика выполнения, которые трудно определить только с помощью здравого смысла и логики. Благодаря тысячам сгенерированных с помощью кода вариаций различных запросов даже, казалось бы, бесполезные индексы могут помочь в некоторых статистических данных и планах запросов, которые в конечном итоге используются в критических запросах.

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

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

Ответы:

8

Очень интересный подход. Мой голос за творчество.

Поскольку вы освободили место, я предполагаю, что исходные индексы больше не на месте? Недостатками отфильтрованных индексов являются:

  • Слишком много из них может привести к тому, что пространство поиска оптимизатора станет слишком большим, что приведет к плохим планам запросов, так как время ожидания оптимизатора истекло
  • Есть несколько ситуаций, когда отфильтрованный индекс даже не будет рассматриваться, даже если не отфильтрованный эквивалент будет. В частности, это может произойти, когда вы получаете хеш-соединение для индексированного столбца или если вы пытаетесь ORDER BY столбца (без фильтра)
  • Параметризация запроса не работает с отфильтрованными индексами (см .: http://www.sqlservercentral.com/blogs/practicalsqldba/2013/04/08/sql-server-part-9-filtered-index-a-new-way- for-performance-Imprommnt / )

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

Томас Кейсер
источник
Msgstr "Параметризация запроса не работает с отфильтрованными индексами". это, вероятно, можно исправить с помощью параметра (перекомпилировать)
MichaelD
2

Томас Кейсер ответит на эту тему намного выше.

Я просто думал о добавлении 2 центов.

Я видел, что некоторые отфильтрованные индексы использовались (показанные в плане выполнения) только тогда, когда вы точно совпадали с предложением where в вашем запросе и где в фильтрованном индексе.

Вы пытались использовать индексированные представления ? редкие столбцы ?

Я считаю, что, поскольку у вас есть только внутренние соединения, вы можете создать индексированное представление, содержащее предложения where ваших отфильтрованных индексов, а затем вы можете использовать представление вместо этого.

Там может быть более одного взгляда. Но так же, как с некластеризованными индексами, слишком много замедлит вашу запись.

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

Тем не менее, насколько я понимаю, ваша главная проблема the null valuesзаключается в том, что я бы предложил вам колонки SPARSE в ваших индексах .

Разреженные столбцы особенно подходят для отфильтрованных индексов

Поскольку я рекламировал разреженные столбцы, я бы не чувствовал себя хорошо, если бы я не рассказал вам и о его ограничениях:

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

Как результат этого

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

и никакие столбцы не могут быть вытолкнуты из строки.

Рассмотрим> пример таблицы с 600 разреженными столбцами типа bigint.

Если имеется 571 ненулевой столбец, то общий размер на диске составляет 571 * 12 = 6852 байта. После включения дополнительных служебных данных строки и разреженного заголовка столбца это увеличивается примерно до 6895 байтов. Страница все еще имеет около 1124 байтов на диске. Это может создать впечатление, что дополнительные столбцы могут быть успешно обновлены. Однако во время обновления в памяти появляются дополнительные издержки, равные 2 * (число непустых разреженных столбцов). В этом примере включение дополнительных служебных данных - 2 * 571 = 1142 байта - увеличивает размер строки на диске примерно до 8037 байтов. Этот размер превышает максимально допустимый размер 8019 байт. Поскольку все столбцы являются типами данных фиксированной длины, их нельзя вытолкнуть из строки. В результате обновление завершается с ошибкой 576.

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

Изменение столбца с разреженного на не разреженный или с не разреженного на разреженный требует изменения формата хранения столбца.

Модуль базы данных SQL Server использует следующую процедуру для выполнения этого изменения:

1 - добавляет новый столбец в таблицу в новом размере и формате хранилища.

2 - Для каждой строки в таблице обновляет и копирует значение, сохраненное в старом столбце, в новый столбец.

3 - Удаляет старый столбец из схемы таблицы.

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

Марчелло Миорелли
источник
1
Здравствуй. Немного опоздал на драку, но да, хотя мы отказались от подхода, описанного в этой теме давным-давно, мы недавно вернулись к нему с более избирательным подходом. По сути, мы рассмотрели статистику использования и бизнес-модель, чтобы подтвердить индексы для каждой таблицы. Затем протестируйте его, добавив новый отфильтрованный индекс на стороне нормального, и проверите, чтобы в течение нескольких недель увидеть, какой из них в конечном итоге использовался. После подтверждения того, что ТОЛЬКО отфильтрованные индексы использовались в новых планах, мы отбросили обычные нефильтрованные.
Кан
1
Кроме того, мы изменили довольно много столбцов на разреженные типы. Однако проблема в том, что, как вы увидите из MSDN, изменение типа столбца на разреженный в основном заставляет воссоздать весь кластерный индекс. Делать это довольно тяжело для больших и сложных столов. Поэтому мы переименовали ограничения и таблицу, создали новую с той же моделью и исходным именем, но с разреженными столбцами, а затем перенесли данные в новую таблицу соответствующими пакетами. Затем однажды проверил, что все в порядке, и все индексы и FK снова на месте, удалили старые таблицы.
Кан
1
Кроме того, в некоторых случаях использование сжатия страниц было гораздо предпочтительнее, поэтому мы в итоге сделали это. Это также удобно, поскольку вы можете просто создать существующий кластерный индекс с DROP_EXISTING = ON, чтобы сделать его намного, намного быстрее, чем идти по разреженному маршруту. Тем более, что это позволяет избежать хлопот, связанных с повторным управлением индексами и FK.
Кан