Тактика нормализации SQL Server: varchar vs int Identity - PullRequest
2 голосов
/ 27 сентября 2008

Мне просто интересно, какое оптимальное решение здесь.

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

Например, я могу иметь

People
======================
name      varchar(10)   
DoB       DateTime    
Height    int  

Phone_Number
======================
name      varchar(10)   
number    varchar(15)

Или я мог бы

People
======================
id        int Identity   
name      varchar(10)   
DoB       DateTime  
Height    int  

Phone_Number
======================
id        int   
number    varchar(15)  

Конечно, добавьте несколько других отношений один-ко-многим.

Что вы все думаете? Что лучше и почему?

Ответы [ 7 ]

10 голосов
/ 27 сентября 2008

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

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

7 голосов
/ 27 сентября 2008

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

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

И, наконец: «ИМЯ» - это зарезервированное слово хотя бы в одной СУБД, поэтому рассмотрите возможность использования чего-то другого, например ПолноеИмя.

6 голосов
/ 27 сентября 2008

Использование любого вида несинтетических данных (то есть чего-либо от пользователя, а не сгенерированных приложением) в качестве PK проблематично; вам нужно беспокоиться о различиях в культуре / локализации, чувствительности к регистру (и других проблемах, зависящих от сортировки БД), может привести к проблемам с данными, если / когда эти введенные пользователем данные когда-либо изменятся и т. д.

Использование данных, не сгенерированных пользователем (последовательные идентификаторы GUID (или непоследовательные, если ваша БД их не поддерживает или вас не волнует разделение страниц) или идентификаторы (если вам не нужны идентификаторы GUID)) намного проще и безопаснее.

Относительно дублирующих данных: я не понимаю, как использование несинтетических ключей защищает вас от этого. У вас все еще есть проблемы, когда пользователь вводит «Боб Смит» вместо «Боб К. Смит» или «Смит, Боб» или «Боб Смит» и т. Д. Управление дублированием необходимо (и в значительной степени идентично) независимо от того, является ли ваш ключ синтетическим или не синтетические, и не синтетические ключи имеют множество других потенциальных проблем, которые синтетические ключи аккуратно избегают.

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

3 голосов
/ 27 сентября 2008

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

Более того, текстовые данные - это огромная боль с точки зрения сравнений, ваша жизнь намного проще, когда вы делаете WHERE id = user_id против WHERE name LIKE inputname (или что-то в этом роде) подобный).

1 голос
/ 28 сентября 2008

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

В вашем вопросе действительно две проблемы. Во-первых, предпочтительнее ли использовать int или varchars для использования в качестве первичных ключей и внешних ключей. Второе - можете ли вы использовать естественные ключи, указанные в определении проблемы, или вам следует сгенерировать синтетический ключ (суррогатный ключ), чтобы заменить естественный ключ.

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

Вопрос о том, действительно ли предоставленный естественный ключ работает как естественный ключ или нет, гораздо важнее. Проблема дубликатов в столбце «имя» - не единственная проблема. Существует также проблема того, что происходит, когда человек меняет свое имя. Эта проблема, вероятно, не проявляется в приведенном вами примере, но она возникает во многих других приложениях баз данных. Примером может служить стенограмма за четыре года всех курсов, пройденных студентом. Женщина может выйти замуж и изменить свое имя в течение четырех лет, и теперь вы застряли.

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

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

1 голос
/ 28 сентября 2008

Одна вещь, которую другие, кажется, не упомянули, состоит в том, что объединения в полях int имеют тенденцию работать лучше, чем объединения в полях varchar.

И я определенно всегда использовал бы суррогатный ключ при использовании имен (людей или предприятий), потому что они никогда не бывают уникальными с течением времени. В нашей базе данных, например, у нас есть 164 имени с более чем 100 экземплярами с одинаковыми именами. Это ясно показывает опасность использования имени в качестве ключевого поля.

1 голос
/ 27 сентября 2008

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

Однако вы не объясняете, что такое «имя». На практике очень редко строка подходит в качестве первичного ключа. Если это имя человека, оно не будет работать в качестве PK, поскольку более одного человека могут иметь одно и то же имя, люди могут менять имена и т. Д.

...