Таблицы без первичного ключа - PullRequest
39 голосов
/ 08 августа 2008

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

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

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

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

Ответы [ 7 ]

32 голосов
/ 08 августа 2008

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

Что касается аргумента GUID vs ID, вы можете найти в Интернете людей, которые клянутся обоими. Меня всегда учили использовать GUID, если у меня нет действительно веской причины не делать этого. У Джеффа есть хороший пост, в котором рассказывается о причинах использования GUID: https://blog.codinghorror.com/primary-keys-ids-versus-guids/.

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

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

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

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

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

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

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

7 голосов
/ 08 августа 2008

Первичный ключ служит трем целям:

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

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

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

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

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

6 голосов
/ 05 августа 2009

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

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

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

Rob

3 голосов
/ 19 марта 2010

Никто не ответил на актуальный вопрос: каковы плюсы / минусы таблицы без NO PK, N CLUSTERED index. На мой взгляд, если вы оптимизируете для более быстрых вставок (особенно для инкрементальной массовой вставки, например, когда вы загружаете данные в непустую таблицу), такая таблица: без кластеризованного индекса, без ограничений, без внешних ключей, без значений по умолчанию и НЕТ Первичный ключ, в базе данных с простой моделью восстановления, является лучшим. Теперь, если вы когда-нибудь захотите запросить эту таблицу (а не сканировать ее полностью), вы можете добавить некластеризованные неуникальные индексы по мере необходимости, но сохранить их на минимальном уровне.

0 голосов
/ 03 ноября 2010

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

0 голосов
/ 08 августа 2008

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

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

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

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

0 голосов
/ 08 августа 2008

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

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