СУБД. Лекция 1

СУБД
Навроцкий Артем
Лекция 1

Знакомство, введение в реляционные базы данных

Правила игры

Слайды доступны по адресу: https://bozaro.github.io/tech-db-lectures/

Контроль знаний

Экзамен ― это уникальная возможность для студента два раза в год узнать что-то полезное хотя бы на несколько дней.
© Французский бизнесмен и творческая личность Джордж Элгози

Семестровый проект

Реализация API для "форума".

API сформулировано в виде Swagger-схемы.

Работа принимается в виде git-репозитория, из которого собирается Docker-контейнер.

Задание расположено по адресу: https://github.com/bozaro/tech-db-forum

Отправная точка: https://github.com/bozaro/tech-db-hello

На чем писать проект?

На "отлично" в прошлых семетсрах были сданы проекты на:

Язык программирования Кол-во
Go19
Java17
Node.js6
Kotlin2
Rust2

"Эталонная" работа реализована на Go и Rust.

О плагиате

Грустный слайд

Период Отчислено Всего %
Весна 2020   41  
Осень 2018 09 42 ~21%
Весна 2018 17 44 ~39%
Осень 2017 11 55 ~20%
Весна 2017 15 44 ~34%
Осень 2016 16 51 ~31%

Интересные факты

1 https://habrahabr.ru/post/26289/
2 https://planet.openstreetmap.org/
Лучше спросить и выставить себя дураком на пять минут, чем не спросить и остаться дураком на всю жизнь.
Народная мудрость

Зачем ввобще нужны СУБД?

Допустим, мы реализуем приложение "Поваренная книга" для хранения рецептов.

Все нетривиальные абстракции дырявы.
© Джоэл Спольски

Стоимость типовых операций

Стоимость операции нс (ns) мкс (µs) мс (ms)
Получение значения из L1 0.5
Ошибка предсказания перехода в CPU 5
Получение значения из L2 7
Mutex lock/unlock 25
Получение значения из RAM 100
Сжатие 1Кб методом Zippy 3 000 3
Отправка 1Кб через 1Гбит/сек сеть 10 000 10
Чтение 4Кб с SSD (случайный доступ) 150 000 150
Чтение 1Мб из RAM (последовательный доступ) 250 000 250
Round trip внутри одного датацентра 500 000 500
Чтение 1Мб из SSD (последовательный доступ) 1 000 000 1 000 1
Позиционирование HDD 10 000 000 10 000 10
Чтение 1Мб из HDD (последовательный доступ) 20 000 000 20 000 20
Round trip между США и Нидерландами 150 000 000 150 000 150
https://gist.github.com/jboner/2841832

Задача курса

Проектирование и диаграммы

SQL

Оптимизация

“Ну и запросы у вас”, - сказала база данных и повисла.

Администрирование

На моей работе самая страшная фраза это: “ребята, за какую дату у нас есть бэкап базы данных?”
© bash.im

High-Load и Big Data

Кратенькая история

Реляционные БД

… многие отдали предпочтение реляционным системам баз данных, поскольку используемый в них стандартизованный язык SQL открывал возможности безболезненного перехода от одной СУБД к другой. Хотя воспользовались ими на практике только единицы, мысль о возможной смене поставщика СУБД, не связанной со сколько-нибудь ощутимыми затратами, согревала всех.
Мартин Фаулер

NoSQL

Литература

Определение БД

База данных (БД)
Это взаимосвязанная информация (данные) об объектах, которая организованна специальным образом и хранится на каком-либо носителе.

Реляционная модель данных

Целое Строка Целое Типы данных
номер имя должность деньги Домены
Отношение
Табельный номер Имя Должность Оклад Премия Аттрибуты
2934 Иванов Инженер 112 40 Кортежи
2935 Петров Вед. Инженер 144 50
2936 Сидоров Бухгалтер 92 35
Ключ

Терминология

Домен
Тип данных, то есть допустимое множество значений.
Кортеж
Множество пар {имя атрибута, значение}, которое содержит одно вхождение каждого имени атрибута, принадлежащего схеме отношения.
Отношение
Множество кортежей (не упорядоченное).
Целостность базы данных
Соответствие имеющейся в базе данных информации её внутренней логике, структуре и всем явно заданным правилам.

Реляционная модель данных

Реляционная модель данных (РМД)
Логическая модель данных, прикладная теория построения баз данных, которая является приложением к задачам обработки данных таких разделов математики как теории множеств и логика первого порядка.

Реляционная модель данных включает следующие компоненты:

Структурный аспект (составляющая)
Данные в базе данных представляют собой набор отношений.
Аспект (составляющая) целостности
Отношения (таблицы) отвечают определенным условиям целостности. РМД поддерживает декларативные ограничения целостности уровня домена (типа данных), уровня отношения и уровня базы данных.
Аспект (составляющая) обработки (манипулирования)
РМД поддерживает операторы манипулирования отношениями (реляционная алгебра, реляционное исчисление).

Реляционная алгебра

Эдгар Франк «Тед» Кодд

Выборка (A WHERE c)

Персоны

Имя Возраст Вес
Harry 34 80
Donald 29 70
Helena 54 54
Peter 34 80

`sigma_("Возраст" >= 34)("Персоны")`

Имя Возраст Вес
Harry 34 80
Helena 54 54
Peter 34 80
SELECT * FROM "Персоны" WHERE "Возраст" >= 34

Проекция (PROJECT A {x, y, …, z})

Персоны

Имя Возраст Вес
Harry 34 80
Donald 29 70
Helena 54 54
Peter 34 80

`Pi_("Возраст", "Вес")("Персоны")`

Возраст Вес
29 70
54 54
34 80
SELECT DISTINCT "Возраст", "Вес" FROM "Персоны"

Объединение (A UNION B)

Персоны

Имя Возраст Вес
Harry 34 80
Donald 29 70
Helena 54 54
Peter 34 80

Персонажи

Имя Возраст Вес
Daffy 24 19
Donald 29 70
Scrooge 81 27

`"Персоны" uu "Персонажи"`

Имя Возраст Вес
Harry 34 80
Donald 29 70
Helena 54 54
Peter 34 80
Daffy 24 19
Scrooge 81 27
SELECT * FROM "Персоны" UNION SELECT * FROM "Персонажи"

Пересечение (A INTERSECT B)

Персоны

Имя Возраст Вес
Harry 34 80
Donald 29 70
Helena 54 54
Peter 34 80

Персонажи

Имя Возраст Вес
Daffy 24 19
Donald 29 70
Scrooge 81 27

`"Персоны" nn "Персонажи"`

Имя Возраст Вес
Donald 29 70
SELECT * FROM "Персоны"
NATURAL JOIN "Персонажи"

Разность (A MINUS B)

Персоны

Имя Возраст Вес
Harry 34 80
Donald 29 70
Helena 54 54
Peter 34 80

Персонажи

Имя Возраст Вес
Daffy 24 19
Donald 29 70
Scrooge 81 27

`"Персоны" \\ "Персонажи"`

Имя Возраст Вес
Harry 34 80
Helena 54 54
Peter 34 80
SELECT * FROM "Персоны"
NATURAL LEFT JOIN "Персонажи"
WHERE "Персонажи" IS NULL

Произведение (A TIMES B)

Мультфильмы

Код_Мульта Название_Мульта
1 The Simpsons
2 Family Guy
3 Duck Tales

Каналы

Код_Канала Название_Канала
1 СТС
2 2x2

`"Мультфильмы" xx "Каналы"`

Код_Мульта Название_Мульта Код_Канала Название_Канала
1 The Simpsons 1 СТС
2 Family Guy 1 СТС
3 Duck Tales 1 СТС
1 The Simpsons 2 2x2
2 Family Guy 2 2x2
3 Duck Tales 2 2x2
SELECT * FROM "Персоны", "Персонажи"

Деление (A DIVIDEBY B)

Мультфильмы

Код_Мульта Название_Мульта Название_Канала
1 The Simpsons RenTV
1 The Simpsons 2x2
1 The Simpsons СТС
2 Family Guy RenTV
2 Family Guy 2x2
3 Duck Tales СТС
3 Duck Tales 2x2

Каналы

Название_Канала
RenTV
2x2

`"Мультфильмы" -: "Каналы"`

Код_Мульта Название_Мульта
1 The Simpsons
2 Family Guy
SELECT "Код_Мульта", "Название_Мульта"
FROM "Мультфильмы"
JOIN "Каналы" USING ("Название_Канала")
GROUP BY "Код_Мульта", "Название_Мульта"
HAVING COUNT(DISTINCT "Название_Канала") = (
    SELECT COUNT(DISTINCT "Название_Канала") FROM "Каналы"
)

Соединение ((A TIMES B) WHERE P)

Мультфильмы

Код_Мульта Название_Мульта Название_Канала
1 The Simpsons 2x2
2 Family Guy 2x2
3 Duck Tales RenTV

Каналы

Код_Канала Частота
RenTV 3.1415
2x2 783.25

`"Мультфильмы" ⋈ "Каналы"`

Код_Мульта Название_Мульта Название_Канала Код_Канала Частота
1 The Simpsons 2x2 2x2 783.25
2 Family Guy 2x2 2x2 783.25
3 Duck Tales RenTV RenTV 3.1415
SELECT *
FROM "Мультфильмы"
JOIN "Каналы" ON ("Название_Канала" = "Код_Канала")

Первичный ключ

Потенциальный ключ

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

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

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

Первичный ключ (англ. primary key)

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

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

Суррогатный ключ

Даже при наличии естественного ключа добавление суррогатного в большинстве случаев оправдано.

UserID E-Mail Пароль Имя Дата
12 tolstoy@mail.ru ***** Толстой Л.Н. 09.09.1828
48 saltykov@inbox.ru ***** Николай Щедрин 27.01.1826
543 fmd@mail.ru ***** Федор Михайлович 11.11.1821
5 sukin_syn@mail.ru ***** Пушкин А.С. 06.06.1799
UserID Привилегии
12 Админ
12 Модератор
48 Модератор
543 Игрок
5 Админ
UserID Разделы
12 Новости
12 Флуд
48 Флуд
48 Юмор
543 E-Mail
5 Поэзия

Типы данных PostgreSQL

NULL

SELECT 1 = NULL, 1 <> NULL, 1 < NULL, 1 > NULL;
1 = NULL 1 <> NULL 1 < NULL 1 > NULL
SELECT 1 IS NULL, 1 IS NOT NULL, NULL IS NULL, NULL IS NOT NULL;
1 IS NULL 1 IS NOT NULL NULL IS NULL NULL IS NOT NULL
0 1 1 0

Числовые

Тип столбца, поля Обьем занимаемой памяти Диапазон допустимых значений
SMALLINT, INT2 2 байта От -32768 до 32767
INTEGER, INT, INT4 4 байта От -2147683648 до 2147683648
BIGINT, INT8 8 байт От -263 до 263 -1
DECIMAL [(M[,D])],
NUMERIC [(M[,D])]
~2 байта на 4 цифры Повышенная точность
более 10000 цифр
REAL 4 байта -3.402823466E+38 до -1.175494351E-38
1.175494351E-38 до 3.402823466E+38
DOUBLE PRECISION 8 байт -1.7976931348623157E+308
до -2.2250738585072014E-308
2.2250738585072014E-308
до 1.7976931348623157E+308
MONEY 8 байт От -92233720368547758.08 до +92233720368547758.07

SMALLSERIAL, SERIAL, BIGSERIAL - то же, но с автоинкрементом.

INT1 и беззнаковые есть в расширении https://github.com/petere/pguint

Бинарные

Тип столбца, поля Обьем занимаемой памяти Диапазон допустимых значений
BIT(N) (N + 7) / 8 байт Битовая строка с фиксированной длиной
BIT VARYING(N), VARBIT(N) Битовая строка с переменной длиной
BOOLEAN 1 байт 0 или 1

Строки

Тип столбца, поля Описание
CHARACTER(N), CHAR(N) Строка фиксированной длины
CHARACTER VARYING(N), VARCHAR(M) Строка переменной длины
TEXT Строковые данные без ограничения длины
BYTEA Двоичный данные без ограничения длины

Дата и время

Тип столбца, поля Размер
TIMESTAMP [ (P) ] [ WITHOUT TIME ZONE ] 8 байт
TIMESTAMP [ (P) ] WITH TIME ZONE 8 байт
DATE 4 байта
TIME [ (P) ] [ WITHOUT TIME ZONE ] 8 байт
TIME [ (P) ] WITH TIME ZONE 12 байт
INTERVAL [ FIELDS ] [ (P) ] 16 байт

Время хранится с точностью до микросекунд.

P - кол-во цифр для хранения дробной части секунд.

WITH TIMEZONE - внутри базы хранится UTC.

Пример схемы базы данных (кортежи)

country

id name
0 Россия
42 Вьетнам
55 Гондурас

region

id country_id name
0 0 Москва и Московская обл.
1 0 Санкт-Петербург и область
395 55 Тегусигальпа

city

id region_id name
1 0 Москва
42 0 Жилево
173 1 Санкт-Петербург
6165 395 Тегусигальпа

Пример схемы базы данных (ER-модель)

Пример схемы базы данных (DDL)


CREATE TABLE country (
  id bigserial NOT NULL PRIMARY KEY,
  name varchar(128) NOT NULL
);

CREATE TABLE region (
  id bigserial NOT NULL PRIMARY KEY,
  country_id bigint NOT NULL,
  name varchar(128) NOT NULL,
  FOREIGN KEY (country_id) REFERENCES country (id)
);

CREATE TABLE city (
  id bigserial NOT NULL PRIMARY KEY,
  region_id bigint NOT NULL,
  name varchar(128) NOT NULL,
  FOREIGN KEY (region_id) REFERENCES region (id)
);

Версионирование схемы БД

Хотелки:

Генерация БД на базе исходного кода

Метод инкрементных изменений

Database
|- Baseline.sql
|- 0001.03.01.sql
|- 0002.03.01.sql
|- 0003.03.01.sql
|- 0004.03.02.sql
|- 0005.03.02.sql
|- 0006.03.02.sql
|- 0007.03.02.sql
CREATE TABLE MigrationHistory (
    Id INT AUTO_INCREMENT PRIMARY KEY,
    MajorVersion VARCHAR(2),
    MinorVersion VARCHAR(2),
    FileNumber   VARCHAR(4),
    Description  VARCHAR(255),
    DateApplied  TIMESTAMP
);

INSERT INTO MigrationHistory (MajorVersion, MinorVersion, FileNumber, Description, DateApplied)
VALUES ('03', '01', '0000', 'Baseline', NOW());

INSERT INTO MigrationHistory (MajorVersion, MinorVersion, FileNumber, Description, DateApplied)
VALUES ('03', '01', '0001', 'Update users table', NOW());

Метод инкрементных изменений

Метод идемпотентных изменений

Database
 |- 3.01
 |   |- Baseline.sql
 |   | - Changes.sql
 |
 | - 3.02
     |- Baseline.sql
     |- Changes.sql
IF NOT EXISTS
(
    SELECT *
    FROM information_schema.tables
    WHERE table_name = 'myTable'
        AND table_schema = 'myDb'
)
THEN
    CREATE TABLE myTable
    (
        id INT(10) NOT NULL,
        myField VARCHAR(255) NULL,
        PRIMARY KEY(id)
    );
END IF;

Метод идемпотентных изменений

Навроцкий Артем
E-mail: bozaro@yandex.ru
Спасибо за внимание!