Перестройте Очень Большой Индекс первичного ключа

13

У меня есть база данных SQL, которая размещена на Azure. Проблема в том, что размер выходит из-под контроля, я могу увидеть до 99% фрагментации в кластерных индексах первичного ключа.

Я могу перестроить все остальные индексы с online=onопцией, и это не повлияет на производительность. Размер одного из индексов PK Clustered превышает 200 ГБ, и для этого a REBUILD...WITH (ONLINE=ON)вызывает блокировку.

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

Какова лучшая стратегия для перестройки больших индексов без простоев на сайте?

Я считаю, что реорганизация не поможет, так как фрагментация составляет 99%. Проблема в том, что стол заблокирован даже в режиме онлайн. Основная проблема заключается в том, что индекс превышает 200 ГБ. Первичный ключ является целым числом.

обидчивый
источник
4
@Techy, даже с высокой фрагментацией, REORGANIZEуменьшит фрагментацию конечных страниц и уменьшит компактность, как REBUILD, впрочем, и менее эффективно. Вы уверены, что большой размер происходит из-за фрагментации? Что такое коэффициент заполнения?
Дан Гузман
Вы знаете, что вызывает фрагментацию? Как скоро после восстановления вы вернетесь на площадь 1? Можете ли вы опубликовать больше информации о вашем столе?
17
2
@Techy Я отредактировал вопрос, чтобы добавить дополнительную информацию на основе ваших комментариев. Было бы полезно, если бы вы также включили в вопрос определение таблицы и дополнительные сведения, относящиеся к «таблице блокируется даже при [перестройке] в сети». Какие виды ожидания вы видите?
AMTwo

Ответы:

9

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

Во-первых, и я не знаю, делаете ли вы это или нет, но, пожалуйста, не думайте, что высокие уровни фрагментации в индексе всегда будут приводить к снижению производительности. Устаревшая статистика (например, sys.dm_db_stats_properties ) и большое количество пустого пространства на странице (т. Е. Столбец avg_page_space_used_in_percent в sys.dm_db_index_physical_stats dmv ) имеют большее отношение к проблемам производительности, чем только фрагментация. Да, сильно фрагментированные индексы будут генерировать больше упреждений при чтении, и вы, как правило, видите устаревшую статистику и более высокие уровни пробелов на странице в сочетании с фрагментацией, но фрагментация напрямую не связана с оптимизацией плана запросов или с тем, сколько памяти загружает индекс с диска будет на самом деле потреблять. На планы запросов влияет статистика, и ваш объем памяти увеличивается с появлением большего количества пустого пространства . Например, индекс, который фрагментирован на 99%, но имеет среднее значение менее 5%. Пробелы и актуальная статистика, скорее всего, не вызовут у вас резких проблем с производительностью по сравнению с плохим планом выполнения из-за устаревшей статистики или постоянной подкачки индекса, который слишком велик для того, чтобы полностью поместиться в памяти, потому что существует значительный объем пустого пространства присутствует на странице.

Если фрагментация действительно является проблемой , вы можете уменьшить ее, ОНЛАЙН, выполнив ALTER INDEX ... REORGANIZEзаявление, определенное Дэном Гусманом в комментариях. Это не создаст такой упорядоченный индекс, как REBUILDоперация, но уменьшит вашу фрагментацию. Ключевым моментом здесь является определение окон более низкого использования в вашей базе данных и запускать его тогда. Это может быть 15 минут или несколько часов, очевидно, чем дольше, тем лучше, но ключевой момент здесь заключается в том, что эта операция не выполняет откат и сохраняет достигнутый прогресс, даже если вы убьете его в середине выполнения.

Если в идеальном мире, где ваша фрагментация была устранена, имеет ли смысл использовать разбиение этой таблицы? База данных SQL Azure допускает разбиение таблиц, и у Microsoft есть отличная статья, в которой изложены некоторые стратегии разделения для базы данных SQL Azure . Если ваши данные не являются летучими, их разбиение может помочь сократить потребности в обслуживании, а в сочетании со сжатием таблиц вы даже сможете уменьшить общий объем памяти. Более ранний ответ Альберто Мурильо намекает на использование горизонтального разбиения основанный на области данных, и этот подход может помочь создать некоторые окна обслуживания для вас, так как ваши данные будут более региональными, а не глобальными.

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

Джон Айсбренер
источник
4

Во-первых, важно учитывать, имеет ли значение фрагментация.

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

Часто люди замечают, что перестройка индекса исправляет проблему производительности. Перестройка индекса также создает свежую статистику. Может случиться так, что реальное исправление - это свежая статистика, а не перестройка индекса. UPDATE STATISTICS...WITH FULLSCANможет быть более дешевым, быстрым и менее навязчивым способом решения той же проблемы с производительностью.

Если у вас нет проблем, вызванных фрагментацией, то вы могли бы потратить значительное время и усилия без какой-либо реальной выгоды.

Во-вторых, существует два вида фрагментации:

  1. Физическая фрагментация. Это то, о чем думает большинство людей, когда они думают о фрагментации. Страницы вышли из строя и должны быть переупорядочены. При сканировании индекса этот тип фрагментации может иногда быть проблемой. Я вообще заметил, что это имеет наибольшее влияние на производительность при физическом чтении. Если вы смотрите на результаты sys.dm_db_index_physical_stats, этот номер является avg_fragmentation_in_percentстолбцом.

  2. Фрагментация низкой плотности. Эта фрагментация вызвана страницами, которые только частично заполнены данными. У вас низкая плотность данных, потому что ваши данные распределены по большему количеству страниц, чем необходимо. В результате для чтения данных требуется больше операций ввода-вывода, поскольку данные распределены по большему количеству страниц, чем необходимо. Это может повлиять как на логическое, так и на физическое чтение. Если вы смотрите на результаты sys.dm_db_index_physical_stats, этот номер является avg_page_space_used_in_percentстолбцом. Этот столбец заполняется только при использовании SAMPLEDили DETAILEDрежиме.

Итак, что вы делаете по этому поводу:

Физическая фрагментация : если вы просто гоняетесь за большими числами avg_fragmentation_in_percent, подумайте, не теряете ли вы время. Убедитесь, что у вас есть фактический запрос, который работает плохо, и используйте тестовую среду, чтобы подтвердить, что вы исправляете проблему, устраняя фрагментацию.

Вы можете решить физическую фрагментацию, выполнив ALTER INDEX...REORGANIZE. REORGANIZEОперация онлайн, перемещение страниц по одному за раз , чтобы реорганизовать их обратно в физический порядок. Если вы уничтожите REORGANIZEоператор на полпути, любая работа, которая уже была выполнена, будет сохранена - будет откатываться только одна страница, которая в данный момент перемещается. Выполнение REORGANIZEоперации с большой таблицей, которая сильно фрагментирована, может потребовать больше общего пространства журнала транзакций, а в режиме полного восстановления может создать значительное количество резервных копий журнала транзакций. Для REORGANIZEсильно фрагментированного индекса может также потребоваться больше времени, чем для REBUILDнего.

Вы часто будете встречаться с советами выполнять операции с REBUILDсильно фрагментированными индексами, а не с. REORGANIZEЭто происходит потому, что восстановление с нуля может быть более эффективным. Однако реорганизация может быть «более оперативной» операцией и иногда предпочтительна даже для сильно фрагментированных индексов.

Фрагментация низкой плотности не может быть исправлена REORGANIZE. Это можно исправить только с помощью ALTER INDEX...REBUILD. Выполнив индекс с ONLINE=ON, вы сможете минимизировать блокировку. Тем не менее, по- REBUILDпрежнему необходимо на мгновение заблокировать, чтобы заменить старый индекс на новый. В очень загруженной системе достижение этой исключительной блокировки иногда может быть проблемой. Вы должны быть в состоянии подтвердить, если у вас возникла эта проблема, используя что-то вроде sp_whoisactive для проверки блокировки во время перестройки и просмотра сведений о блокировках и ожиданиях. Использование этой WAIT_AT_LOW_PRIORITYопции может быть полезно, если вы знаете, что наступает период низкого уровня использования, и ваша перестройка может «проскользнуть» для этого обмена, когда активность падает достаточно низко для достижения этой блокировки. Обратите внимание, что длительныйREBUILDОперация также будет длительной открытой транзакцией. У длительных открытых транзакций могут быть свои проблемы, связанные с использованием / повторным использованием журнала транзакций. Если вы используете зеркалирование или группы доступности, существуют также соображения относительно повторного выполнения журнала транзакций на вторичной реплике.

AMtwo
источник
Фрагментация низкой плотности (так называемая «внутренняя фрагментация») часто фиксируется с помощью REORGANIZE. С BOL : «Реорганизация также сжимает индексные страницы». Ну, так что пока текущий индекс FILLFACTOR будет позволять плотность, которую вы ищете.
Грейнджер
2

уведомление

После этого комментария:

Вы потеряете строки, вставленные во время копирования. Если вы хотите предотвратить это, заблокировав таблицу, то вы столкнетесь с той же проблемой, что и ОП, указанная в его вопросе. Также 200Gb не придет бесплатно :-) - Marco 5 сентября 17 в 11:18

... Я вижу, как этот подход не будет работать.

Я оставлю этот ответ как пример того, чего не следует делать.


Если у вас есть лишние 200 ГБ свободного пространства в вашей базе данных Azure, вы можете получить хитрость при «перестроении», скопировав ваши данные в совершенно новую таблицу и упорядочив ее там.

Пытаться:

  • Скриптинг LiveTableв пустуюNewTable
  • копирование LiveTableвNewTable
  • переименование LiveTableвOldTable
  • переименование NewTableвLiveTable

Очевидно, используйте имя вашей таблицы вместо LiveTable.

Oreo
источник
Орео, я бы использовал тот же подход, что и вы. Даже если во время копирования вставлены строки, вы можете добавить их позже, когда NewTable будет переименован в LiveTable. Главная проблема, которую вы здесь избегаете - это длительное время простоя. Вы могли бы даже скопировать его (скопировать в / в). Это не такая плохая идея, поэтому я тоже не понимаю, что такое понижающий голос :-)
Koen D
1

В идеале, если индекс хорошо спроектирован, нам не нужно возиться с механизмом блокировки.

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

Я не уверен, какую версию SQL Server вы используете, но вы можете попробовать следующее в 2012 году:

  • SET DEADLOCK_PRIORITY LOW - Это говорит движку, что перестройка индекса должна стать жертвой тупика, когда / если он произойдет.

  • MaxDOP = 1 - Значение MaxDOP ограничивает общее количество логических процессоров, используемых параллельно для создания индекса (2005 г. и выше - только версия Enterprise).

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

Начиная с 2014 года, существует следующая опция, которая в основном сообщает движку, что нужно продолжить выполнение других сеансов и ожидание операции индексирования в сети:

(WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF))
GPep
источник
0

Я использовал тот же подход, что и Oreo, описанный выше, с большим успехом! Единственное, чего не хватает, так это того, что вам нужно запустить скрипт обновления после того, как вы скопировали данные и сделали последнее переименование.

Обновление будет выглядеть так:

Insert from OldTable into LiveTable
  Where not exists (select From OldTable Where LiveTable.Key = OldTable.Key)

Если Key - это столбец Identity, вам нужно использовать немного другой подход.

SBB
источник
Как отмечается в ответе Орео, его метод не будет работать, если в исходную таблицу все еще добавляются данные, если только вы не заблокируете исходную таблицу, которая не соответствует цели упражнения
Том V - попробуйте topanswers.xyz
-2

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

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

Надеюсь это поможет.

Альберто Морильо
источник