SQL-запросы. Стоит ли использовать ID в качестве информационного поля?
- Категория: Код
- – Автор: Игорь (Администратор)
В рамках данной статьи я рассмотрю вопрос стоит ли использовать ID в качестве информационного поля, а так же какие при этом могут возникнуть подводные камни при использовании SQL-запросов.
Если смотреть разные методологии построения реляционных баз данных, то нередко можно встретить указание того, что часть информационных полей можно и даже нужно использовать в качестве первичных ключей, при условии, что они уникальны в рамках таблицы. Однако, практика показывает, что это не всегда хорошая идея.
Примечание: Под информационным полем в данной статье подразумевается поле с важными данными, которые в последствии будут использоваться человеком.
Банальный пример это использование целочисленных полей в качестве первичных ключей. Особенно, если у вас пара сотен тысяч записей, зависимых таблиц десяток другой и исходный уникальный признак представляет собой, к примеру, строковое поле размером 50 символов. Причина проста, поиск по целочисленным ключам будет происходить существенно быстрее. При этом вы всегда можете достроить уникальный индекс по изначальному полю.
Однако, в данном примере, важно отметить, что введенный первичный ключ лишь является техническим полем, которое по сути не несет никакой информационной нагрузки. Ведь исходную строчку таблицы человек всегда будет ассоциировать именно с исходным уникальным признаком.
Примечание: Под техническим полем в данной статье подразумевается поле, которое используется только на уровне БД для обеспечения связей между таблицами и которое не представляет интереса для человека.
Другое же дело, когда техническое поле начинает использоваться в качестве информативного. Чтобы легче было понять, рассмотрим ситуацию.
Представьте, что вам необходимо создать небольшую систему учета хранения книг в кладовке. Суть проста. Нужно регистрировать кто, когда и какую книгу принес, а затем кто, когда и какую книгу взял. Чтобы не сильно усложнять систему и не совсем путаться будем считать что одной таблицы для решения хватит. Просто будет указываться признак приходной это документ или выходной. Так же для введения уникальности записей вы ввели автоинкрементное целочисленное поле ID.
В итоге получится что-то вроде такой таблицы Reg:
ID | Date | Book | FIO | Is_Return |
---|---|---|---|---|
1 | 2020.02.12 | Колобок | Вова | 0 |
... | ... | ... | ... | ... |
233 | 2022.02.12 | Азбука | Колян | 1 |
Книг мало, людей тоже немного заходит, в общем получалась простая и замечательная система. При этом несложно заметить, что поле Date чисто для справки, так как именно порядок ID определяет наличие или отсутствие книги (или ее нескольких копий), ведь брать и возвращать книгу можно в один и тот же день.
Проходит время, вы научились одному из языков программирования и создали простой сайт. Добавили несколько отчетов различного вида. Например, книги на руках, самые популярные книги и так далее.
Так же вы решили разнообразить свой сайт и добавить возможность оставлять рецензии о факте возврата или получения бумажного творения, чтобы, например, в последствии понимать хотите ли вы человеку давать книгу. Надписи вроде "Пришел негодяй таки, а я так скучал по колобку". Так же для комфорта вы предусмотрели возможность оставлять несколько комментариев.
Соответственно, вы создаете табличку Comment вроде этой:
Reg_ID | Comment_ID | Text |
---|---|---|
1 | 1 | Эх, взяли Колобка |
1 | 2 | Нужно будет проверить корешок по возврату |
... | ... | ... |
201 | 444 | Заметка вторая: - перепроверил книгу, часть листов замяты((( |
Потом вы решили добавить изображения, потом еще что-то придумали. В общем, у вас получилось около десятка таблиц, которые зависят от ID из таблицы Reg.
А теперь разберем несколько проблем, которые легко могут возникнуть:
1. Допустим, некто взял книгу в то время, когда вы занимались чем-то полезным, и не сказал вам об этом. Прошли года и он пришел к вам вернуть книгу. В такой ситуации у вас возникает проблема. С одной стороны, вы можете просто добавить две строки с получением и возвратом, указав корректные даты. С другой стороны, так как поле Date таблицы Reg чисто для справки, то важно, чтобы запись о выдачи книги имела корректный ID (где-то в середине). В противном случае у вас будут неувязки, например, в отчетах. К примеру, отчет "все взятые книги в хронологическом порядке" будет показывать некорректные данные, ведь поле Date не использовалось в сортировке в SQL-запросах.
Как бы вы не поступили в данной ситуации, в любом случае такой простой факт приведет к массе потраченного времени. Если вы просто добавите строчки, то придется переписывать и проверять все SQL-запросы, чтобы поле Date так же входило в сортировку (плюс, вероятно, еще и для поля Date нужно будет индекс делать). Если заниматься переписыванием всех идентификаторов, то это также может занять существенное количество времени, ведь придется отключать все индексы и ограничения, сдвигать нумерацию, а затем снова все возвращать.
2. Представьте, что вы весьма педантичный человек и поэтому ведете так же бумажный журнал, где для каждой записи оставляете целый лист. Так же в связи с тем, что экземпляров книг может быть несколько, вы вместе с книгой выдаете еще и номер записи, то есть ID. К вам пришел суеверный человек, которому попался, к примеру, номер "13". После долгих обсуждений, вы решили завести дополнительную запись с номером "14". Встает вопрос, что делать с записью "13". Вы можете удалить запись, но в таком случае в вашем бумажном журнале будет пропущен целый лист. Другой вариант, вы можете просто подождать другого человека, выдать ему "13" номер и подкорректировать данные, но нет гарантий, что еще кто-либо придет в этот день. Кроме того, во время ожидания данные в базе получаются некорректными, так как 13 и 14 записи регистрируют взятие 2-х экземпляров, хотя по факту вы отдали только одну книгу.
3. Представьте, что к вам пришел именинник и просит в честь его дня рождения выдать ему номер с его днем рождения. Вот такой вот незатейливый человек. И вы в ходе душевного порыва идете ему навстречу. Однако, возникает проблема - до необходимого числа нужно еще ввести 254 записи. Кроме того, что вам придется все эти 254 записи вручную добавлять и удалять, всегда есть шанс, что вы так же можете удалить запись и с нужным номером. Не сложно догадаться, что раз поле ID автоинкрементное, то в последнем случае придется еще и вручную в базу данных лезть.
Существуют и другие момент, но даже этих достаточно, чтобы увидеть, что использование ID в качестве информационного поля далеко не всегда является хорошей идеей. Ведь если бы еще в момент создания первой таблицы Reg были введены такие поля как timestamp (дата создания записи) и name (уникальное наименование записи), то всех этих проблем легко было бы избежать. И скорость оставалась бы быстрой за счет технического поля ID и проблем бы с записями не было.
Если же переносить эти примеры на реальные системы учета, то такие недостатки легко могут вылиться в существенные по времени их решения проблемы. Поэтому старайтесь придерживаться здравого смысла и использовать технические поля в качестве полей данных только в тех случаях, когда это действительно возможно.
☕ Понравился обзор? Поделитесь с друзьями!
Комментарии / отзывы