столбцы идентификаторов или кластерные первичные ключи / согласованность базы данных - PullRequest
1 голос
/ 02 марта 2010

Если бы у меня была таблица со столбцами:

  • Исполнитель
  • Альбом
  • Песня
  • NumberOfListens

... лучше поместить кластерный первичный ключ в Artist, Album и Song или иметь столбец id с автоинкрементом и установить уникальное ограничение для Artist, Album и Song.

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

Ответы [ 5 ]

5 голосов
/ 02 марта 2010

Я бы никогда не поставил первичный ключ на столбцы длинного текста, такие как: Исполнитель, Альбом и Песня. Используйте идентификатор автоматического увеличения, который является кластеризованным PK. Если вы хотите, чтобы «Исполнитель», «Альбом» и «Песня» были уникальными, разместите уникальный индекс на всех трех. Если вы хотите выполнять поиск по Альбому или Песне, независимо от независимого Исполнителя, вам потребуется индекс для каждого, который использует PK, поэтому наличие небольшого PK экономит вас на индексе друг друга. Экономия заключается не только в дисковом пространстве, но и в кеше памяти, а также в увеличении количества ключей на странице.

1 голос
/ 02 марта 2010

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

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

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

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

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

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

Марк

0 голосов
/ 02 марта 2010

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

Artists (
    ArtistID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    ArtistName varchar(100) NOT NULL)

Albums (
    AlbumID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    ArtistID int NOT NULL,
    AlbumName varchar(100) NOT NULL,
    CONSTRAINT FK_Albums_Artists FOREIGN KEY (ArtistID)
        REFERENCES Artists (ArtistID))

Songs (
    SongID int NOT NULL IDENTITY(1, 1) PRIMARY KEY CLUSTERED,
    AlbumID int NOT NULL,
    SongName varchar(100) NOT NULL,
    NumberOfListens int NOT NULL DEFAULT 0
    CONSTRAINT FK_Songs_Albums FOREIGN KEY (AlbumID)
        REFERENCES Albums (AlbumID))

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

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

Вы должны быть осторожны с кластеризацией ключей. Если вы кластеризуетесь на ключе, который даже не является удаленно последовательным (а имя исполнителя, альбома и песни определенно считается непоследовательным), то в итоге вы получите разбиение страницы и другие неприятности. Ты не хочешь этого. И, как говорит Марк, копия этого ключа добавляется в каждый индекс, и вы определенно не хотите этого, когда ваш ключ имеет длину 300 или 600 байт.

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

CREATE UNIQUE INDEX IX_Artists_Name ON Artists (ArtistName)
CREATE UNIQUE INDEX IX_Albums_Artist_Name ON Albums (ArtistID, AlbumName)
CREATE UNIQUE INDEX IX_Songs_Album_Name ON Songs (AlbumID, SongName)
    INCLUDE (NumberOfListens)

Теперь этот запрос будет быстрым:

SELECT ArtistName, AlbumName, SongName, NumberOfListens
FROM Artists ar
INNER JOIN Albums al
    ON al.ArtistID = ar.ArtistID
INNER JOIN Songs s
    ON s.AlbumID = al.AlbumID
WHERE ar.ArtistName = @ArtistName
AND al.AlbumName = @AlbumName
AND s.SongName = @SongName

Если вы посмотрите план выполнения, вы увидите 3 индекса поиска - это так быстро, как вы можете его получить. Мы гарантируем точно такую ​​же уникальность, как и в оригинальном дизайне и , оптимизированном по скорости. Что еще более важно, он нормализован, поэтому и исполнитель, и альбом имеют свою особую индивидуальность, что значительно облегчает управление в долгосрочной перспективе. Гораздо проще найти «все альбомы исполнителя X». Гораздо намного проще и быстрее искать "все песни в альбоме Y".

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

0 голосов
/ 02 марта 2010

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

0 голосов
/ 02 марта 2010

Кластерные индексы отлично подходят для запросов на основе диапазона. Например, дата регистрации или дата заказа. Помещение одного в Artist, Album и Song [вероятно] вызовет фрагментацию при вставке новых строк.

Если ваша БД поддерживает это, добавьте некластеризованный первичный ключ в Artist, Album и Song и назовите его хорошим. Или просто добавьте уникальный ключ для Artist, Album и Song.

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

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