Почему SQL Server работает быстрее, когда вы индексируете таблицу после ее заполнения?
У меня есть sproc, который помещает записи 750K в временную таблицу через запрос в качестве одного из своих первых действий. Если я создаю индексы в таблице temp перед заполнением, этот элемент занимает примерно в два раза больше времени, чем при индексировании после заполнения таблицы. (Индекс является целым числом в одном столбце, индексируемая таблица представляет собой всего два столбца, каждое из которых содержит одно целое.)
Мне это кажется немного, но тогда у меня нет самого твердого понимания того, что происходит под капотом. У кого-нибудь есть ответ на это?
Ответы
Ответ 1
Если вы создаете кластерный индекс, это влияет на то, как данные физически упорядочиваются на диске. Лучше добавить индекс после факта и позволить механизму базы данных изменять порядок строк, когда он знает, как распределяются данные.
Например, скажем, вам нужно было построить кирпичную стену с пронумерованными кирпичами, чтобы те, у кого наибольшее число, были внизу стены. Было бы трудной задачей, если бы вы просто передали кирпичи в случайном порядке, по одному - вы не знали бы, какие кирпичи будут самыми высокими, и вам придется разорвать стену и перестраивать его снова и снова. Было бы намного легче справиться с этой задачей, если бы у вас были все кирпичи, выстроенные впереди вас, и могли бы организовать вашу работу.
Как и для механизма базы данных - если вы сообщите ему о всей работе, это может быть намного более эффективным, чем если бы вы просто кормили его строкой за раз.
Ответ 2
Это потому, что сервер базы данных должен выполнять вычисления каждый раз, когда вы вставляете новую строку. В принципе, вы в конечном итоге переиндексируете таблицу каждый раз. Это не похоже на очень дорогостоящую операцию, и это не так, но когда вы делаете это, многие из них вместе, вы начинаете видеть влияние. Вот почему вы обычно хотите индексировать после того, как вы заполнили свои строки, поскольку это будет просто одноразовая стоимость.
Ответ 3
Подумайте об этом таким образом.
Учитывая
unorderedList = {5, 1,3}
orderedList = {1,3,5}
добавить 2 в оба списка.
unorderedList = {5, 1,3,2}
orderedList = {1,2,3,5}
Какой список, по вашему мнению, проще добавить?
Btw, упорядочивающий ваш вход до загрузки, даст вам импульс.
Ответ 4
Вы никогда НИКОГДА не создадите индекс на пустой таблице, если вы собираетесь массивно загрузить его сразу же.
Индексы должны поддерживаться по мере изменения данных в таблице, поэтому представьте себе, что для каждой вставки таблицы таблица пересчитывается (что является дорогостоящей операцией).
Сначала загрузите таблицу и создайте индекс после завершения загрузки.
Это была разница в производительности.
Ответ 5
После выполнения больших операций манипулирования данными вам часто приходится обновлять базовые индексы. Вы можете сделать это, используя инструкцию UPDATE STATISTICS [table].
Другой вариант - сбросить и воссоздать индекс, который, если вы делаете большие вставки данных, скорее всего, сделает вставки намного быстрее. Вы можете даже включить это в свою хранимую процедуру.
Ответ 6
это связано с тем, что если данные, которые вы вставляете, не соответствуют порядку индекса, SQL придется разбивать страницы, чтобы освободить место для дополнительных строк, чтобы логически их объединить
Ответ 7
Это связано с тем, что, когда SQL Server индексирует таблицу с данными, она может производить точную статистику значений в индексированном столбце. В некоторые моменты SQL Server будет пересчитывать статистику, но когда вы выполняете массивные вставки, распределение значений может измениться после того, как статистика была рассчитана в последний раз.
Тот факт, что статистика устарела, может быть обнаружена в Query Analyzer. Когда вы видите, что в определенной таблице число ожидаемых строк значительно отличается от фактического количества обрабатываемых строк.
Вы должны использовать UPDATE STATISTICS для пересчета распределения значений после того, как вы вставляете все данные. После этого не должно наблюдаться разницы в производительности.
Ответ 8
Если у вас есть индекс в таблице, то при добавлении данных в таблицу SQL Server придется переупорядочить таблицу, чтобы освободить место в подходящем месте для новых записей. Если вы добавляете много данных, ему придется переупорядочивать его снова и снова. Создав индекс только после загрузки данных, повторный заказ должен произойти только один раз.
Конечно, если вы импортируете записи в индексном порядке, это не имеет большого значения.
Ответ 9
В дополнение к служебным данным индекса выполнение каждого запроса в качестве транзакции - плохая идея по той же причине. Если вы запускаете куски вставок (скажем, 100) в течение 1 явной транзакции, вы также должны увидеть увеличение производительности.