Таблицы без основного ключа

У меня есть несколько таблиц, единственными уникальными данными которых являются столбец uniqueidentifier (Guid). Поскольку указатели не являются последовательными (и они генерируются на стороне клиента, поэтому я не могу использовать newsequentialid()), я сделал непервичный, некластеризованный индекс в этом поле идентификатора, вместо того, чтобы давать таблицам кластерный первичный ключ.

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

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

Каковы ваши мысли? Если таблицы имеют первичные ключи? Или это нормально, чтобы не иметь каких-либо кластеризованных индексов, если нет разумных столбцов для индексации этого пути?

Ответ 1

При работе с индексами вы должны определить, для чего будет использоваться ваша таблица. Если вы в первую очередь вставляете 1000 строк в секунду и не выполняете никаких запросов, то кластеризованный индекс является хитом производительности. Если вы делаете 1000 запросов в секунду, то отсутствие индекса приведет к очень плохой производительности. Лучшее, что нужно делать при настройке запросов/индексов, - это использовать анализатор запросов и SQL Profiler в SQL Server. Это покажет вам, где вы столкнулись с дорогостоящими сканированием таблиц или другими блокаторами производительности.

Что касается аргумента GUID vs ID, вы можете найти людей в Интернете, которые клянутся обоими. Меня всегда учили использовать GUID, если у меня нет повода для этого. У Джеффа хорошая статья, в которой рассказывается о причинах использования GUID: http://www.codinghorror.com/blog/archives/000817.html.

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

[Изменить] @Matt, после того, как я провел еще несколько исследований по обсуждению GUID/ID, я столкнулся с этим сообщением. Как я уже упоминал ранее, нет истинного правильного или неправильного ответа. Это зависит от ваших конкретных потребностей в реализации. Но это довольно веские причины использовать GUID в качестве первичного ключа:

Например, существует проблема, известная как "горячая точка", где определенные страницы данных в таблице находятся в относительно высоком разрешении валюты. В основном, то, что происходит, это большая часть трафика на столе (и, следовательно, блокировки на уровне страницы) происходит на небольшой площади таблицы, к концу. Новые записи всегда будут идти в эту точку доступа, потому что IDENTITY - это генератор последовательных чисел. Эти вставки неприятны, потому что им нужна эксклюзивная блокировка страницы на странице, к которой они добавлены (точка доступа). Это эффективно сериализует все вставки в таблицу благодаря механизму блокировки страницы. NewID(), с другой стороны, не страдает от горячих точек. Значения, сгенерированные с использованием функции NewID(), являются только последовательными для коротких всплесков вставок (где функция вызывается очень быстро, например, во время многорядной вставки), что приводит к тому, что вставленные строки распространяются случайным образом на страницах данных таблицы из всех в конце - таким образом, исключая горячую точку из вставок.

Кроме того, поскольку вставки распределены случайным образом, вероятность разделения страниц значительно снижается. В то время как разрыв страницы здесь и там не слишком плох, эффекты быстро складываются. С IDENTITY, страница Fill Factor довольно бесполезна в качестве механизма настройки и может также быть установлена ​​на 100% - строки никогда не будут вставлены ни на одну страницу, кроме последней. С помощью NewID() вы действительно можете использовать Fill Factor в качестве инструмента для обеспечения эффективности. Вы можете установить Fill Factor на уровень, который приблизительно соответствует расчетному росту объема между индексами перестроек, а затем планировать перестройки в непиковые часы с использованием dindex. Это эффективно задерживает показы производительности разделов страниц до тех пор, пока не будет достигнуто пиковое время.

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

Еще одним огромным преимуществом использования GUID для ПК является тот факт, что ценность действительно гарантирована уникальной - не только среди всех значений, сгенерированных этим сервером, но и всех значений, генерируемых всеми компьютерами - будь то ваш сервер db, веб-сервер, сервер приложений или клиентский компьютер. Практически каждый современный язык имеет возможность генерировать действительный guid now - в .NET вы можете использовать System.Guid.NewGuid. Это ОЧЕНЬ удобно при работе с кэшированными наборами данных master-detail в частности. Вам не нужно использовать сумасшедшие временные схемы манипуляции только для того, чтобы связать ваши записи вместе, прежде чем они будут совершены. Вы просто получаете совершенно новый новый Guid от операционной системы для каждого нового значения постоянной записи в момент создания записи.

http://forums.asp.net/t/264350.aspx

Ответ 2

Первичный ключ выполняет три цели:

  • указывает, что столбец (столбцы) должен быть уникальным
  • указывает, что столбец (столбцы) должен быть не нулевым.
  • документируйте, что это уникальный идентификатор строки

Первые два могут быть указаны многими способами, как вы уже сделали.

Третья причина хорошая:

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

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

Ответ 3

Просто прыгаю, потому что Мэтт немного поманил меня.

Вам нужно понять, что хотя кластерный индекс по умолчанию помещается в первичный ключ таблицы, эти два понятия являются отдельными и должны рассматриваться отдельно. CIX указывает способ хранения и ссылки данных в NCIX, тогда как PK обеспечивает уникальность для каждой строки, удовлетворяющей ЛОГИЧЕСКИМ требованиям таблицы.

Таблица без CIX - это просто куча. Таблица без ПК часто считается "не таблицей". Лучше всего разобраться в концепциях PK и CIX, чтобы вы могли принимать разумные решения в дизайне базы данных.

Rob

Ответ 4

Никто не ответил на фактический вопрос: какие плюсы/минусы таблицы с индексом NO PK NOR CLUSTERED. На мой взгляд, если вы оптимизируете более быстрые вставки (особенно инкрементный объемный ввод, например, когда вы загружаете объемную нагрузку в непустую таблицу), такая таблица: без кластеризованного индекса NO, ограничений NO, NO Foreign Keys, NO Default и NO Primary Key, в базе данных с простой моделью восстановления, является лучшим. Теперь, если вы когда-нибудь захотите запросить эту таблицу (в отличие от ее сканирования полностью), вы можете захотеть добавить некластеризованные неидеальные индексы по мере необходимости, но сохраните их до минимума.

Ответ 5

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

Вместо этого первичный ключ должен быть минимальным набором атрибутов (обратите внимание, что большинство СУБД будет использовать составной первичный ключ), который однозначно идентифицирует кортеж.

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

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

Ответ 6

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

Ответ 7

Поскольку вы выполняете репликацию, ваши правильные идентификаторы - это что-то, что можно избежать. Я бы сделал ваш GUID основным ключом, но некластеризованным, поскольку вы не можете использовать newsequentialid. Это ставит меня как ваш лучший курс. Если вы не сделаете это ПК, но поместите на него уникальный индекс, рано или поздно это может привести к тому, что люди, которые поддерживают систему, не понимают отношения FK, правильно вводящие ошибки.