Что происходит во время «больших» вставок в таблицу с кластерным составным ключом?

8

Мои знания SQL ограничены, поэтому используемые мной термины, скорее всего, неправильные.

У меня есть таблица, в которой будут храниться результаты тестов для нескольких мест.

Тесты будут записываться в разные базы данных в разных местах (без подключения к сети), и «основное» место будет регулярно «импортировать» результаты тестов из других мест.

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

Размер строки будет от 80 до 100 байт, а количество результатов теста не должно превышать нескольких миллионов. Типичный «импорт» вставит от 50 до 100 тысяч результатов из другого места.

Что будет во время импорта? Будет ли SQL «перемещать» существующие строки для поддержки кластеризации, или это позволит таблице стать «фрагментированной»? Может ли это привести к значительному снижению производительности, если импорт выполняется по одной строке за раз? Должен ли я просто не беспокоиться о порядке строк и просто добавить столбец идентификаторов в качестве первичного ключа и индекс в столбце Дата, чтобы помочь с моими запросами?

Саша К
источник

Ответы:

19

Святая корова, у тебя здесь много вопросов. Давайте разберемся с этим.

Вопрос: Будет ли SQL «перемещать» существующие строки для поддержки кластеризации, или это позволит таблице стать «фрагментированной»?

Думайте о базе данных как о наборе страниц - буквальных кусочках бумаги, разложенных на вашем столе. Подумайте о словаре сейчас. Если вы хотите добавить больше слов в словарь, вы можете добавить их на место, если на страницах было свободное место.

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

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

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

Может ли это привести к значительному снижению производительности, если импорт выполняется по одной строке за раз?

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

Что происходит, когда я запрашиваю данные?

Вы не спрашивали об этом, но я спрашиваю это для вас, хахаха.

Вспомните о последствиях наших вставок. Теперь у нас есть словарь, который в основном упорядочен, но когда вы доберетесь до нескольких словарных пунктов, вам придется перейти назад, чтобы прочитать несколько других страниц. Если все эти страницы кэшируются в вашей памяти (ОЗУ, буферный пул и т. Д.), Тогда издержки не будут такими большими. В любом случае, большая часть доступа к памяти является случайной - это не то, что SQL Server сохраняет ваш словарь в памяти по порядку.

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

Должен ли я просто не беспокоиться о порядке строк и просто добавить столбец идентификаторов в качестве первичного ключа и индекс в столбце Дата, чтобы помочь с моими запросами?

Бинго: в этом разница между физическим дизайном базы данных и логическим дизайном базы данных. Первоначально программистам приходится сильно беспокоиться о физическом проектировании баз данных, но пока ваша база данных меньше, скажем, 100 ГБ, вы можете, так сказать, исправлять логический дизайн в посте. Поместите поле идентификации для начала, кластеризируйте его, а затем, после нескольких месяцев работы, пересмотрите дизайн индекса, чтобы максимизировать производительность.

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

Брент Озар
источник
1
По одной вставке был теоретический вопрос. С точки зрения производительности, мне показалось сомнительным, что «строки хранятся на диске физически в том же порядке, что и кластерный индекс», как вы читали в большинстве мест.
Саша К
Я пойду за личность столбца. Данные будут добавлены «в конце» и, естественно, отсортированы по дате. Одни и те же даты для разных мест не будут "близко друг к другу", но это не имеет значения для меня.
Саша К