СоХабр закрыт.

С 13.05.2019 изменения постов больше не отслеживаются, и новые посты не сохраняются.

H TL;DR — реляционные СУБД для тех, кто не смог в черновиках Tutorial

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



В этом выпуске — таблицы, индексы, ключи, нормальные формы и немного практики. Целевая аудитория — интересующиеся школьники или IT-студенты, прогулявшие лекцию по БД.


Матчасть


В реляционной СУБД хранится таблица (теоретики называют «отношение», relation — отсюда и «реляционная модель»), у нее есть колонки (они же «атрибуты») и строки (или «кортежи»).

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

Если конкретное значение в столбце (-ах) индекса приводят к конкретной единственной строке таблицы (например, столбец «номер паспорта» приводит к одному человеку), то по таким столбцам логично создать первичный ключ (primary key, PK). Обычно бывает наборот: СУБД сами покрывают первичный ключ уникальным индексом (бывают неуникальные), если на этапе создания таблицы объявить primary key [1].

Таблицы могут быть связаны между собой: «один к одному», «один ко многим», «многие ко многим» [2]. Для связей понадобятся ключи: первичный ключ одной таблицы связан с тем же значением внешнего ключа (foreign key, FK) другой таблицы.

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

Практика


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

Можно создать таблицу пользователей (users) и таблицу ролей (roles). Согласно условию, пользователь и его роли связаны «один ко многим». Понятие «кардинальность связи» показывает, сколько именно ролей у конкретного пользователя.

Что с этим знанием можно сделать? Подключиться к БД и воспользоваться SQL!
-- создать таблицы:
CREATE TABLE users (
   user_id int NOT NULL PRIMARY KEY, -- суррогатный первичный ключ
   user_name char (30) NOT NULL 
 );

CREATE TABLE roles (
   user_id int FOREIGN KEY REFERENCES users (user_id), -- внешний ключ
   role_name char (30) NOT NULL 
 );

-- заполнить
INSERT INTO users (user_id, user_name) values (1, 'Вася');
INSERT INTO roles (user_id, role_name) values (1, 'Администратор');

-- в зависимости от вашей IDE (если autocommit не включен) 
-- может понадобиться явно завершить транзакцию
COMMIT; 

-- посмотреть, все ли на месте
SELECT u.user_name, r.role_name 
  FROM users u, roles r
 WHERE u.user_id = r.user_id;


Эти же данные можно было сложить в одну таблицу или в три, что упростило или усложнило бы запрос на выборку. База данных должна быть в нормальной форме — их много, но на практике используются первые три НФ [3].

Для тех, кто дочитал до конца


[1] Больше одного PK на той же таблице создавать нельзя, но можно несколько FK.
[2] Связь «один к одному» — редкий случай (когда широкую таблицу из многих колонок разорвали на несколько мелких). Связь «многие ко многим» в чистом виде не встречается — её делают через три таблицы и две связи «один ко многим».
[3] В реальных приложениях идеальной нормализации не бывает — например, обязательно кто-то возьмет и сделает журнал аудита с колонкой в XML или JSON… но про проектирование и бизнес-сценарии мы поговорим в следующих сериях.

комментарии (19)

+7
DrPass ,  
Если бы так же преподавали математику в школе, то уроки звучали бы как-то так: «Здравствуйте дети, я ваш новый учитель математики. Смотрите, вероятность выпадания орла на монетке равна примерно 0.5, интеграл от e в степени х равен е в степени х плюс константа, а ещё в теории катастроф есть точки бифуркации»
0
zip_zero ,  
Рисуем сову…

Если серьезно, уроки математики звучали бы примерно так:

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

Рассмотрим что попроще: рациональные числа. Сегодня у нас есть сложение, вычитание, умножение и деление. На следующих занятиях мы изучим возведение в степень и корень.

А теперь — к практике, я вам покажу особую роль нуля…

Для тех, кто досидел до конца — то же самое, но про иррациональные числа...
0
maaGames ,  
Что такое число? Что такое меньше? Что такое операция? Почему рациональные проще? xD
+1
babylon ,  

@zip_zero первое о чём надо говорить когда имеешь дело с SQL и NOSQL DB это то что и те и те оперируют с записями и атрибутами как с множествами. Именно отсюда вытекает или не вытекает реляционность.

0
zip_zero ,  
Это второе, о чем нужно говорить: как раз перед тем, как рассказывать и показывать про виды объединений (join).
Если с ходу сказать студенту: «записи — это множества», могут не понять. А нужно, чтоб поняли :)
+2
Femistoklov ,  
Для тех, кто дочитал до конца
Это шутка такая?
0
zip_zero ,  
Цикл статей задумывался как состоящий из трех частей: теория, практика и заключение.

«Для тех, кто дочитал до конца» — к сожалению, не шутка, но ирония. Почти сарказм. Дело в том, что по разным причинам люди не читают текст от начала до конца, если он длиннее сообщения в Твиттер. Проматывают, даже если специально зашли его почитать.
0
Listrigon ,  
Что-то из статьи так и не понял чего же я не смог…
0
zip_zero ,  
Не смог… понять :)
0
BerkutEagle ,  
Некорректно выбран пример с ролями пользователей — тут больше подходит связь много-много, ведь Марья Ивановна, например, тоже учитель математики.
0
zip_zero ,  
Пример выбран корректно для своей цели: я ждал этот комментарий и специально упомянул «многие ко многим» в конце статьи.

Действительно, если мы бы захотели знать, сколько людей у нас — учители математики, физики, текущая модель была бы не очень удобна. И таки да, для этого вводится третья таблица:
CREATE TABLE users (
   user_id int NOT NULL PRIMARY KEY, 
   user_name char (30) NOT NULL 
 );

CREATE TABLE roles (
   role_id int NOT NULL PRIMARY KEY,
   role_name char (30) NOT NULL 
 );

CREATE TABLE users_roles (
   user_id int FOREIGN KEY REFERENCES users (user_id), 
   role_id int FOREIGN KEY REFERENCES roles (role_id)
);
0
AlexeySachkov ,  

Какое-то мутной определение первичного ключа.
Вроде как правильнее сказать что первичный ключ — это минимальный набор полей (имеется в виду столбцов таблицы), однозначно определяющий запись в таблице (строку)

0
zip_zero ,  
Согласен.
0
leahch ,  
Это как это PK у нас только один в/на таблице?! Составных PK не знаем? А про нормализацию ни слова? А срезы? А транзакции? А блокировки? А типы изоляции?! Это крайне важно, ну кроме срезов! Статья, извиняюсь, пустая и однобокая.
0
zip_zero ,  
Незачем так негодовать. Знаем.

Первичный ключ на таблице один (он не зря первичный). Он может быть простым (одна колонка) и составным (несколько). Про нормализацию умышленно ни слова — выдана ссылка на Вики для интересующихся.

ACID, MVCC и все связанные темы (транзакции, стратегии блокировки, изоляция) нужно рассматривать отдельно и подробно. Нормализацию — тоже. Я думаю, это попадет в следующую мою статью. Важно понять. что включить в нее в первую очередь, поэтому ваш отзыв очень кстати.

Спасибо.
+1
zip_zero ,  
Кстати, по поводу изоляции. Как часто вам в реальной жизни приходилось осознанно менять уровень изоляции с read committed на, допустим, serializable? Как бизнес-логика коверкалась от аномалий фантомных или неповторяемых чтений?
0
zip_zero ,   * (был изменён)
Я понимаю, что статья короткая и технически ни о чем. Но получилась странная картина: 27 человек добавили в избранное и 7 человек молча проголосовали в «минус».

Что это значит? Те, кому статья нравится, не имеют кармы, чтобы голосовать.У кого карма есть — слишком заняты, чтобы давать комментарии. А ведь мнение важно в первую очередь…
+1
michael_vostrikov ,  
Это значит, что кто-то добавил в избранное со страницы со списком статей, чтобы потом почитать комменты.
Какое мнение вам нужно? Тут даже комментировать нечего. У вас в статье около 20 предложений. Ничего нового в ней нет, такой информации много по всему интернету. Вы бы лучше в одной статье сразу все написали, получилась бы какая-никакая шпаргалка.
0
fishcorporated ,  
да уж…