| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > СУБД, общие вопросы > Юзать или не Юзать составные PrimaryKey? |
| Автор: Lamak 3.11.2006, 11:33 |
| На моей новой работе юзают много разных БД Так вот (1) в базах часто используются таблицы у которых PrimaryKey состоит из 3-х ,5-ти, а то и 7-ми полей. (2) а ещё есть таблицы с 20-30 полями. Моё мнение: ето бардак - плохо спроектированые БД В универе нас препод учил что ето не есть хорошо Да и в книге "Конноли Т., Бегг К. Базы данных: проектирование, реализация и сопровождение."(читал года два назад)я кажись неппомню чтобы рекомендовали такое универ,книги - это по теории на работе - это на практике Поетому я и сомневаюсью Получается что теория и практика расходятся Вопрос: Так рекомендуется или не ракомендуется юзать составные PrimaryKey? Люди поделитесь своим опытом! Неужели у вас тоже встречаются такие таблицы(с (1) и (2)) |
| Автор: LSD 3.11.2006, 11:45 |
| В общем случае: выборка данных по составному PK дольше, индексы занимают больше места и как следствие памяти сервера. Поэтому когда есть возможность использовать простой PK, то лучше использовать его. Но иногда составной PK бывает и полезным. В частности: уникальный ID записи для всех таблиц базы, или даже уникальный в пределах нескольких баз (нужно для репликации данных). Или вынести в PK некое условие, по которому часто осуществляется фильтрация данных. |
| Автор: JUmPER 3.11.2006, 11:49 |
| если есть составной ключ из нескольких полей, то лучше (в целях оптимизации и удобочитаемости) завести таблицу соответствий простой ключ <--> составной ключ и вместо составнго юзать соответствующий ему простой... |
| Автор: chief39 5.11.2006, 16:00 |
| Составные - правильнее с т.з. теории. Но если это строки.. и полей несколько... Сам понимаешь, с интежером ни в какое сравнение по скорости... Лучше "по соседству" влепить на эти значимые столбцы уникальный констрейнт. А при выборках пользовать интежер в качестве примари ки. Везде, где работал, на больших продакшнах именно так и делали. Но это лишь моя точка зрения |
| Автор: Shiny 6.11.2006, 12:26 |
| Lamak, очень многое зависит от проекта и его назначения. Есть проекты, в которых невозможно обойтись без составных ключей (та же репликация), есть проекты, в которых таблицах которых нужны именно 20-30 полей (например детальные анкетные данные о человеке - адрес, телефон, дата рождения - человек один, разбивать на мелкие таблички не нужно) В общем, я считаю, что ты слишком пытаешься обобщить ситуацию под теорию. Разберись в сути проектов и приведи более детальный пример - тогда можно будет говорить более конкретно. |
| Автор: chief39 6.11.2006, 13:27 | ||||
Вобщем,
За редкими исключениями - это плохо с т.з. производительности. Желателен служебный ID. А вот тут следует хорошо подумать:
нужны то нужны... Но следовало бы оценить частоту использования конкретных данных. Иногда следует применять вертикально разбиение таблицы: ФИО, паспорт, некий код etc. - держать в первой таблице. Во вторую вынести год рождения, адрес, дату регистрации, прописку, семейное положение и прочую мелочь. Связать их отношением 1 к 1 по искусственному примари ки. Если 90% запросов - просто список людей без дополнительных данных - скорость возрастёт. А остальные 10% запросов вполне могут делать джоин этих таблиц в одну. Опять-таки, можно посадить вьюху, которая будет представлять как бы неразбитую таблицу джойном. Вполне возможно, что стоит разбить таблички для скорости.... http://www.olap.ru/basic/saharov.asp немного написано по этому поводу |
| Автор: Shiny 6.11.2006, 14:10 | ||
| Опять же - зависит от проекта. У меня одинаково часто запрашивали инфу как по параметрам "пол-возраст", "город - месяц рождения", "тип населённого пункта - наличие домашнего телефона" и т.д. и т.п. Заморачиваться с разделением не стоило - никакой выгоды не вижу, приоритетные поля выделить нельзя. Поэтому всё равно считаю что всё зависит от конкретного проекта
Составной праймари кей необходимен для правильной обработки данных, полученных с реплицированных баз. Служебный АйДи(ГУИД) добавляет сам сервер, но использовать его для последующего анализа нереально - это всё равно что varchar(16), скорость обработки нулевая.... Другое дело что потом для правильной работы того же олапа нужно делать из 4-х полей составного ключа одно уникальное вычисляемое поле, а это уже кто как исхитрится |
| Автор: chief39 6.11.2006, 15:39 | ||||
Ессно (
)
Я говорил о простом интежере, который создан нами и не несёт никакой информации реального мира. Но является уникальным. И добавляет его не сам сервер, а мы. Нашими механизмами. Вроде как номер паспорта для человека: вроде бы никакой инфы о человеке толком - но уникален для него везде и вполне переносим. |
| Автор: Shiny 6.11.2006, 17:08 | ||
Согласна - работает для всех НЕреплицируемых баз. Для них можно даже и на сервер положиться - айдентити при отсутствии репликации меня ещё не подводило. Для реплицируемых - фикус |
| Автор: chief39 6.11.2006, 17:27 | ||
Угу |
| Автор: TaNK 11.11.2006, 13:15 |
| я например считаю юзать PK - необходимо, но не так чтобы их было слишком много, их должно быть столько скоко необходимо для работы с базой, для добавления, изменения и удаления....с InterBase хвататет и пару ключей, один PK и парочку FK |
| Автор: Romkin 14.11.2006, 16:51 |
| TaNK, Что значит "не слишком много"? И что значит "с InterBase хвататет и пару ключей, один PK и парочку FK"? Чем этот сервер БД так уж отличается от всего остального? На таблицу может быть один PK. И желательно, чтобы он всегда был. Иначе потом будет немного больно ;) Идея, что нужно иметь в первичный ключе одно поле, и при этом автоинкремент, пришла из файловых БД - там за целостностью ручками следить надо было. Естественно, искусственные ключи нужны. Но и составные - тоже нужны, в связке мастер-деталь. У меня иногда получается иерархия до 4-5 деталей, последовательно, т.е. Мастер -> Деталь -> Деталь ... И если бы я делал в каждой детали простой ключ из одного автоинкрементного поля - ну это просто нарушение целостности! Как понять, какому мастеру принадлежит деталь N-го уровня?! Я считаю, что уж идентифицирующая связь должна приводить к автоматическому наследованию PK мастера в PK зависимой таблицы. И такие соображения, что индексы получаются объемными тут, имхо, вообще не должны приводиться: нормальная БД справится. Зато запросы будут гораздо проще. |
| Автор: LSD 14.11.2006, 17:09 | ||
1. При чем тут нарушение целостности? foreign key на что? 2. Если в середине этой цепочки один child сменит parent-а, то всю нижележащую цепочку править? |
| Автор: Romkin 14.11.2006, 17:55 | ||
Нарушение логической целостности: глядя на запись подчиненной таблицы можно определить только запись непосредственного предка. То есть, я имею в виду случай, когда 1. имеется иерархия подчинения 2. на каждом уровне первичный ключ - простой уникальный идентификатор 3. имеется ссылка только на непосредственного предка. И получается, что для того, чтобы найти группировку более высокого уровня, требуется пройти всю цепочку. А если ключ наследуется по порядку - четко видно всю иерархию, и промежуточные уровни можно опускать. При этом возникает два случая: а. Связь по альтернативному ключу. Зачем? Как раз лишний индекс и образуется. б. Связь неидентифицирующая (в детали ссылка на мастера не входит в первичный ключ). Но это же совсем не то, что подразумевалось! Это - не связь мастер-деталь, это лукап. А насчет смены парента - вообще говоря, идентифицирующая связь не предполагает этого. Например, возьмем простой документ, счет, состоящий из заголовка и содержимого. Явная связь мастер-деталь. И пересоединять содержимое документа к другому заголовку - достаточно бессмыссленная операция. Разумеется, бывают и другие случаи - но в этих случаях смена парента - редкая операция, тут можно и поправить. Тем более, что и делать-то ничего не надо особо: констрейнт обновит автоматом. Дело в том, что на мой взгляд, разработчик БД должен стараться внести в структуру БД как можно больше знаний о предметной области. И как раз для этого-то составные ключи и используются. |
| Автор: LSD 14.11.2006, 18:02 |
| Что-то я не пойму твою мысль. Дай пример таблиц, ключей и констрайнов. |
| Автор: Dremlin 14.11.2006, 18:14 |
| LSD, а чего там не понять? ты делаешь: tbl1(id1), tbl2(id2, id1), tbl3(id3, id2), tbl4(id4, id3)... etc , а человеку удобнее: tbl1(id1), tbl2(id2, id1), tbl3(id3, id2, id1), tbl4(id4, id3, id2, id1)... etc хотя смысл подобных манипуляций от меня ускользает... |
| Автор: Romkin 14.11.2006, 18:39 | ||
Сорри, наоборот (первичные ключи): tbl1(id1), tbl2(id1, id2), tbl3(id1, id2, id3), tbl4(id1, id2, id3, id4)... В результате, при возникновении вопроса "мне нужны записи из tbl4, которые относятся к данной записи из tbl1 (то есть известно значение id1)", достаточно смотреть только на tbl4 |
| Автор: LSD 14.11.2006, 22:02 |
| Т.е. в tbl4 - колонки (id1, id2, id3, id4) будут составным первичным ключем? А какие будут foreign key? |
| Автор: Romkin 14.11.2006, 22:18 |
| Так они очевидны - первичный ключ предка Например, у tbl4 это (id1, id2, id3), унаследованная часть первичного ключа. |
| Автор: LSD 14.11.2006, 22:27 |
| А foreign key? |
| Автор: Romkin 14.11.2006, 23:38 | ||
| я о foreign key и говорю Вот например отрывок:
и тд. |
| Автор: LSD 15.11.2006, 00:05 |
| Теперь возник вопрос: зачем надо было включать id1 и id2 в primary key? Простой пользователь не должен синтетические ключи видеть вообще, а DBA не так уж и часто надо любоваться на PK, индекс по такому ключу менее эффективен. Вообщем я вижу только недостатки. |
| Автор: Romkin 15.11.2006, 09:37 |
| Я уже сказал: упрощаются запросы. Это как минимум. Например, если возникает задача выбрать записи из tbl4, которые принадлежат определенной записи из tbl1, в моем случае нужно сделать простой запрос к tbl4, id1 там есть и индексировано. Если бы этих полей не было, пришлось бы делать join трех таблиц, это - чтение трех индексов. Простой пользователь, разумеется, ключи не видит, а разработчик - у меня несколько людей смотрит структуру БД. И когда, смотря на таблицу, ты можешь сразу сказать, какое место в иерархии она занимает и с какими таблицами соединена, имхо, это большой плюс. ТО, что индекс менее эффективен - а насколько? Во сколько раз индекс по 4 полям integer менее эффективен, чем по 1-2? |
| Автор: LSD 15.11.2006, 11:11 | ||||
Каким образом включение id1, id2, id3 в primary key упрощает запросы? Добавлено @ 11:12
Это зависит от кучи факторов, и просто так сказать, что он менее эффективен в 2,36 раза нельзя. |
| Автор: Romkin 15.11.2006, 12:44 | ||||||||
Рассмотрим следующий скрипт (примерный, многие поля в таблицах опущены):
Задача: Вывести из tbl1 Name и для каждого Name показать его сумму Price из таблицы tbl4. Решение:
Теперь рассмотрим другой скрипт, где ссылки - только на непосредственного предка:
Нужно то же самое. Можно, я не буду писать запрос с join всех этих таблиц? У меня получается, что в первом варианте скорость выше, несмотря на то, что индекс используется частично. На практике, конечно, немного сложнее (у меня tbl2 - соединение многие-многие двух таблиц, там еще другие запросы), но запросы иногда нужны примерно такие. |
| Автор: LSD 15.11.2006, 13:02 | ||
| Я не об этом. В это топике обсуждается составные primary key, а не организация foreign key. Я спрашивал зачем нужно было включать поля id1, id2, id3 в primary key, а не зачем ты их добавил в таблицу tbl4 или сделал по ним foreign key. По поводу эффективности, не скажу за все СУБД, но в Oracle вот такой primary key:
будет использоваться только если идет запрос по первым полям, т.е.: id1 или id1, id2 или id1, id2, id3 или id1, id2, id3, id4. Если выборка идет по другой комбинации полей (например id2, id3), то индекс использоваться не будет, и будет full scan. |
| Автор: Romkin 15.11.2006, 13:52 | ||||||
Да, именно так. И именно поэтому я сразу указал порядок полей. И можно заметить, что в моих запросах в условии стоит первое поле первичного ключа.
Хм. А кто начал спрашивать в десять вечера, какие foreign key у меня есть? Включаю я их в PK для по нескольким причинам: 1. Это набор полей, однозначно идентифицирующий запись. Можно заметить, я нигде не упоминал, что все они автоинкрементные. На мой взгляд, подобную иерархию на автоинкрементах и представить-то сложно 2. Для сохранения целостности: этим я явно показываю, какие записи могут быть в таблице. Разумеется, можно сделать, напрмиер в tbl4 один ключ id4 (если, подчеркиваю, это автоинкремент) и сделать ограничение уникальности (альтернативный ключ). Но это мне не надо: тогда индекс первичный ключа вообще в запросах участвовать не будет! Он не несет нужной информации. Только при выборке на клиент данной записи для редактирования, разве что (я не заржавею, написав для этого условие по 4 полям для составного ключа). 3. Для указания разработчику, с чем повязана эта таблица и как. Включение этих полей в ПК сразу подразумевает, что это именно подчиненная таблица, связь идентифицирующая, и вся работа с ней должна проходить с использованиемее предков. Плюс - перемещение записи между предками либо недопускается в реальности, либо чрезвычайно редкий сервис (я уже приводил пример, счет, состоящий из заголовка и содержимого. Нафиг содержимое перемещать? Или, например, это просто детализация записи мастера - тоже перемещать нет смысла). Конечно, разработчик всегда может посмотреть на схему данных, полная - на стене висит, два листа А0. И есть поблочная, листиков 30 А4... Как показывает прктика, уж лучше чтобы БД максимально подсказывала, что в ней есть. 4. Как показывает практика, выборки при схеме с составными ключами идут практически все по ним! Либо по первым полям, либо по всем. Немногие исключения - именно при унаследованной связи многие-многие, например, рассмотрим частично модифицированную схему:
Обращаю внимание: tbl3 - фактически связь двух таблиц, tbl2 и tblN (не показана, первичный ключ id3) поэтому в tbl4 унаследованы поля из этих же таблиц. При возникновении задачи "выбрать все поля из tbl4 для данной записи в tblN" поиск по первичному ключу не пойдет, поэтому введен индекс, второе поле в котором для, эээ... у меня id4 не автоинкремент, и тоже участвует, как правило, в запросах |
| Автор: chief39 15.11.2006, 14:00 |
В большинстве. Может, есть исключения, но я их пока не знаю... |
| Автор: LSD 16.11.2006, 12:44 | ||||
Я уже понял, что это было опрометчиво Мне не нравится:
|
| Автор: Romkin 16.11.2006, 14:39 | ||||
Возможно. Смотря какая методика репликации. У меня в основной задаче вообще репликацию не сделаешь, не имеет смысла При перемещении к другому родителю особых проблем не вижу, апдейтятся же первичные ключи подчиненных таблиц, кому какое дело, какое у них значение? И как сделать связь многие-многие без конкатенации первичных ключей связываемых таблиц в таблицу связи? При этом же никого не пугает, что при перемещении он модифицируется... Почему? Есть же какие-то причины
В какой-то мере - да. Но опять же не вижу особых причин так не делать. Ограничение уникальности должно быть, почему нужно его делать не первичным ключем (при условии, что данные-то не изменятся)? У меня все поля в РК - статичны. Ну почти все ;) На самом деле, это не так. Я тоже ожидал большого количества полей при проектировании, но, как правило, их 4-5 получается максимально. Да, у меня есть пара таблиц с количеством полей в ключе 6-7, но это, скорее, исключение. Как правило, получается, что связи идут так, что поля сливаются. Разумеется, там, где нужно, я применяю неидентифицирующую связь, но, на мой взгляд, именно там, где надо: у пользователя она отображается в подавляющем большинстве случаев чем-то вроде лукапа. |
| Автор: Shaggie 20.6.2007, 08:09 |
| Почитал... интересно... есть вопрос. Предположим, существует такая БД:
Логично предположить, что между ними организованиа связь по типу many-to-many. Поэтому создаётся дополнительная таблица "Следователь_Дело", в которой находятся ссылки на первичные ключи двух основных таблиц. Как наиболее эффективно организовать эти ссылки? Создать независимый первичный ключ, а ссылки представить в виде foreign key? Или НЕ СОЗДАВАТЬ отдельный первичный ключ, а реализовать его за счёт композитного ключа этих двух ссылок? |
| Автор: LSD 20.6.2007, 09:28 | ||||
Разве одно дело могут вести два следователя?
Композитный первичный ключ, на основе двух полей. Т.к. в данном случае будет меньше обращений к диску при чтении данных. |
| Автор: Shaggie 20.6.2007, 09:30 |
| Спасибо, я понял |
| Автор: Deniz 21.6.2007, 06:00 |
| LSD, Могут, не одновременно, в некотором промежутке времени, причем дело может и к первому вернуться, и нужно хранить всю историю. Вот была http://www.ibase.ru/devinfo/NaturalKeysVersusAtrificialKeysByTentser.html давно, но все же |