SQL Server: покрытие индексов, включая все столбцы?


9

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

Цель состоит в том, чтобы улучшить производительность SELECT независимо от того, какой запрос генерируется в базе данных, поскольку доступ осуществляется через ORM, который по умолчанию (но не всегда) извлекает все столбцы. Мы ожидаем, что побочными эффектами этого являются повышенные требования к хранилищу (возможно, значительно) и дополнительное время для INSERT / UPDATE / DELETE.

Вопрос в том, является ли это разумной стратегией? У нашей команды есть история с SQL Server, но нет участников, которые бы считали себя экспертами по его внутреннему поведению (хотя был поднят вопрос, что если бы эта стратегия была оптимальной, не будет ли она по умолчанию сейчас?). Какие еще побочные эффекты (использование ЦП / памяти / TempDB сервера базы данных и т. Д.) Нам следует ожидать, или некоторые из наших предположений выше неверны?

Кроме того, приложение может быть установлено как на локальном сервере SQL Server (версии с 2012 года), так и на SQL Azure - если мы будем готовы к любым различиям между этими двумя или дополнительным побочным эффектам на Azure в результате этого подходить?

Ответы:


8

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

это разумная стратегия?

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

Но чтобы сделать это со всеми индексами, я бы точно так же сказал, что нет.

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

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

Это обычная модель с плохо оптимизированным использованием ORM (или просто наивных ORM), и в этих случаях я видел, как советник по индексам SQL Server (и подобные сторонние инструменты) предлагает индексы с большим количеством INCLUDEстолбцов d, поэтому я согласен с вашим Предположение, что именно поэтому индексы были созданы таким образом.

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

Также помните, что ORM может не выделять все столбцы всех таблиц, к которым обращается запрос, так что преимущество может иметь место только для главной цели текущего запроса, а более крупные индексы могут оштрафовать запрос, когда другие объекты используются для фильтрации. но не возвращая данные ( SELECT * FROM table1 WHERE id IN (SELECT someID FROM table2 WHERE someColumn='DesiredValue')возможно).

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

должны ли мы быть готовы к любым различиям между двумя [on-prem & AzureSQL]

В целом, я думаю, что соображения здесь будут одинаковыми в каждом случае, хотя любые избыточные затраты памяти / ввода-вывода, вызванные большими индексами, могут быть более четко видны в Azure, где вы можете настроить уровень обслуживания, и, следовательно, стоимость инфраструктуры легче, чем имея относительно фиксированный набор аппаратного ресурса. При использовании стандартных / премиальных уровней вместо цен на основе vcore затраты на ввод-вывод в стандарте окажут на вас большее влияние, так как наценка включает значительно больше операций ввода-вывода на DTU. Если вы используете резервное копирование нескольких регионов или избыточность или другие нелокальные функции в Azure, то может потребоваться пропускная способность, связанная с дополнительным пространством, занимаемым неоправданно широкими индексами.


Мы пошли дальше и сделали это удаление. Побочным эффектом было то, что в некоторых таблицах SELECTбез указания ORDER BYначал возвращаться те же строки, что и раньше, но в другом произвольном порядке.
T2PS

Это не неожиданно. Порядок результатов без 'ORDER BY' по определению не определен и может изменяться каждый раз, когда планировщик запросов решает использовать другой подход, который он может сделать в результате изменений индекса или изменений шаблонов данных по мере роста. Другие факторы могут внести такое изменение в порядок позднее, даже без этого изменения. Если вы полагаетесь на порядок вывода выписки, даже поверхностно, тогда вам нужно включить 'ORDER BY', чтобы гарантировать это.
Дэвид

О, безусловно. Предыдущий комментарий был скорее напоминанием для тех, кто найдет этот ответ позже.
T2PS

5

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

В большинстве случаев это не разумная стратегия. Причина в том, что в общих базах данных OLTP строки, возвращаемые конечному пользователю, не будут много. (Обобщение)

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

Рассмотрим следующую таблицу, возвращающую множество столбцов, where SelectiveIDField= ...

select columnA,columnC, ... columnZ
FROM dbo.BigTable
Where SelectiveIDField= '225122141';

Если при поиске будет возвращена только одна строка selectiveIDField, является ли поиск дополнительного ключа такой плохой вещью? (предполагаю, что у вас есть кластерные индексы, в противном случае поиск RID)

Он просто сделает один дополнительный поиск ключа, одно дополнительное выполнение + оператор соединения. Даже если это будет 10 или даже 100, будет ли это иметь огромное влияние? Это также зависит от того, насколько выполнен ваш запрос и насколько важно время выполнения.

В случае, если он незначителен, просто создайте индекс SelectiveIDFieldи назовите его день: он не должен стоить выигрыша от чтения по сравнению с потерями на запись.

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

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