Основные ключи SQL

Итак, мы с коллегой спорим о том, какой путь лучше для генерации первичных ключей, которые являются GUID.

Мы используем.NET 4.0 с Entities 4 и используем хранимые процедуры для выбора / вставки / обновления.

Он хочет создать первичный ключ GUID в коде и передать его обратно как часть вставки, используя класс Guid или / и используя некоторый созданный класс Sequential GUID.

Я хочу, чтобы GUID создавался SQL Server при вставке с использованием newid() или newsequentialid().

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

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

Итак, какой метод лучше для одиночных вставок? Какой метод лучше для нескольких вставок в транзакции?

2 ответа

Решение

Идентификаторы GUID могут показаться естественным выбором для вашего первичного ключа - и, если вам действительно нужно, вы, вероятно, можете поспорить, что он будет использоваться для ПЕРВИЧНОГО КЛЮЧА таблицы. Что я настоятельно рекомендую не делать, так это использовать столбец GUID в качестве ключа кластеризации, что SQL Server делает по умолчанию, если вы специально не запретите это делать.

Вам действительно нужно держать в стороне две проблемы:

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

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

По умолчанию первичный ключ в таблице SQL Server также используется в качестве ключа кластеризации, но это не обязательно должно быть так! Я лично видел значительное увеличение производительности, когда разбивал предыдущий первичный / кластерный ключ на основе GUID на два отдельных ключа - первичный (логический) ключ на GUID и ключ кластеризации (упорядочения) на отдельном INT IDENTITY(1,1) столбец.

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

Да я знаю - есть newsequentialid() в SQL Server 2005 и более поздних версиях - но даже это не является действительно и полностью последовательным и, следовательно, также страдает от тех же проблем, что и GUID- чуть менее заметно. Если вы настаиваете на GUID, то хотя бы используйте newsequentialid() метод на сервере!

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

Быстрый расчет - использование INT и GUID в качестве первичного ключа и ключа кластеризации:

  • Базовая таблица с 1 000 000 строк (3,8 МБ против 15,26 МБ)
  • 6 некластеризованных индексов (22,89 МБ против 91,55 МБ)

ИТОГО: 25 МБ против 106 МБ - и это только на одном столе!

Еще немного пищи для размышлений - отличные вещи Кимберли Триппа - прочитайте, прочитайте еще раз, переварите! Это на самом деле индексное Евангелие SQL Server.

Марк

Когда у меня возникают подобные вопросы, я говорю себе: "SQL Server хорош в наборах, поэтому позвольте ему делать то, что хорошо", а иногда "1 - это просто особый случай N".

Какой метод лучше для одиночных вставок?

Время одной вставки будет одинаковым для любого из ваших подходов для синхронного вызова SQL. Однако "его" подход создаст вам больше проблем с временем поиска в будущем, потому что его последовательный метод guid будет не так хорош, как серверы sql (и вы, вероятно, потеряете глобальную уникальность). Это также разделит вашу кодовую базу, когда вам неизбежно потребуется сделать несколько вставок.

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

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

Если бы это был я, я бы создал SP, который принимает сериализованную коллекцию объектов для вставки, выполняет вставку / выборку с предложением output, посмотрите "Пример B. Использование OUTPUT с идентификаторами и вычисляемыми столбцами" на этой странице, и пусть sql На сервере создайте GUID (если вы застряли на нем) и вернитесь к клиенту или выполните следующую инструкцию в SP, чтобы вставить дочерние строки на основе выходной таблицы, которую вы сгенерировали.

Другие вопросы по тегам