Почему SQL Server работает быстрее, когда вы индексируете таблицу после ее заполнения? - PullRequest
15 голосов
/ 26 августа 2008

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

Мне это кажется немного странным, но тогда у меня нет четкого понимания того, что происходит под капотом. У кого-нибудь есть ответ на это?

Ответы [ 9 ]

42 голосов
/ 26 августа 2008

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

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

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

6 голосов
/ 26 августа 2008

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

3 голосов
/ 26 августа 2008

Думайте об этом так.

С учетом
unorderedList = {5, 1,3}
orderList = {1,3,5}

добавить 2 в оба списка.
unorderedList = {5, 1,3,2}
orderList = {1,2,3,5}

Какой список, по-вашему, легче добавить?

Кстати, порядок ввода перед загрузкой даст вам импульс.

3 голосов
/ 26 августа 2008

Вам НИКОГДА не следует создавать индекс для пустой таблицы, если вы собираетесь массово загружать его сразу после этого. Индексы должны поддерживаться при изменении данных в таблице, поэтому представьте, что для каждой вставки в таблицу индекс пересчитывается (что является дорогостоящей операцией). Сначала загрузите таблицу и создайте индекс после окончания загрузки. В этом разница в производительности.

2 голосов
/ 26 августа 2008

После выполнения больших операций с данными вам часто приходится обновлять базовые индексы. Это можно сделать с помощью оператора UPDATE STATISTICS [table].

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

1 голос
/ 27 августа 2008

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

1 голос
/ 26 августа 2008

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

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

1 голос
/ 26 августа 2008

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

Тот факт, что статистика устарела, можно обнаружить в Query Analyzer. Когда вы видите, что при сканировании определенной таблицы ожидаемое количество строк сильно отличается от фактического количества обработанных строк.

Вы должны использовать СТАТИСТИКА ОБНОВЛЕНИЯ для пересчета распределения значений после вставки всех данных. После этого никакой разницы в производительности не должно наблюдаться.

1 голос
/ 26 августа 2008

это потому, что если данные, которые вы вставляете, не в порядке индекса, SQL придется разделить страницы, чтобы освободить место для дополнительных строк, чтобы логически их объединить

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...