Skip to content
Gallery
Theory for java developer
Share
Explore

icon picker
DB

Базы Данных

Реляционные vs не реляционые
Реляционные БД
Не реляционные БД
1
Что будем делать с данными и какими данными - определлено заранее. Важна целостность данных. Для сложных действий с данными. Экспертиза комманды.
Что будем делать с данными и какими данными не определлено заранее или часто меняется. Лучше простые действия с данными. Важна скорость обработки данных и масштабируемость. Экспертиза комманды.
2
Везде похожий язык запросов SQL
У каждой свой язык запросов и конструкции
3
Хранят данные в формате столбцов и строк
Много разновидностей баз: файлы, json, графы...
4
Масштабируются по вертикали и сложно по горизонтали (репликация, шардирование)
Легко масштабируются горионтально
5
Строгая структура данных. Соблюдается ACID. Структура редко меняется.
Можно хранить коллекии с разными атрибутами и полями. Нет жестких ограничений. Хранение не структурированных данных.
6
Есть шаблоны для доступа к данным которые иногда работают быстрее sql
There are no rows in this table

Типы связей таблиц - 

Золотой ключик - «один». Знак бесконечности - «многие»
image.png
image.png
one-to-many(левый рисунок) Нужно реализовать некую БД, которая ведет учет данных о пользователях. У пользователя есть: имя, фамилия, возраст, номера телефонов. При этом у каждого пользователя может быть от одного и больше номеров телефонов (многие номера телефонов). Один учитель и предметы преподавания.
many-to-many(правый рисунок) Для реализации связи многие ко многим нам нужен посредник между двумя рассматриваемыми таблицами. Он должен хранить два внешних ключа, первый из которых ссылается на первую таблицу, а второй — на вторую. Учители и ученики.
one-to-one - можно сказать, что — это разделение одной и той же таблицы на две.
primary key отличается от ограничения unique лишь тем, что не может принимать значения null.
image.png

Нормализация БД

1НФ - в каждой клеточке таблицы только одно значение. Строки не повторяются.
2НФ - 1НФ. Есть первичный ключ. Все атрибуты зависят от primary key целиком, не от части.
3НФ - 2НФ. Атрибуты зависят только от primary key. Отсутствует транзитивная функциональная зависимость (transitive functional dependency). A -> B, B->C, A->C – не 3НФ.
4НФ (Бойса Кода) - 3НФ. Ключевые атрибуты не д.

Дернормализация

Сохранение исторических данных. Данные меняются с течением времени, но может быть нужно сохранять значения, которые были введены в момент создания записи. Например, могут измениться имя и фамилия клиента или другие данные о его месте жительства и роде занятий. Задача должна содержать значения полей, которые были актуальны на момент создания задачи. Если этого не обеспечить, то восстановить прошлые данные корректно не удастся. Решить проблему можно, добавив таблицу с историей изменений. В таком случае SELECT-запрос, который будет возвращать задачу и актуальное имя клиента будет более сложным. Возможно, дополнительная таблица — не лучший выход из положения.
Повышение производительности запросов. Некоторые запросы могут использовать множество таблиц для доступа к часто запрашиваемым данным. Пример — ситуация, когда необходимо объединить до 10 таблиц для получения имени клиента и наименования товаров, которые были ему проданы. Некоторые из них, в свою очередь, могут содержать большие объемы данных. При таком раскладе разумным будет добавить напрямую поле client_id в таблицу products_sold.
Ускорение создания отчетов. Бизнесу часто требуется выгружать определенную статистику. Создание отчетов по «живым» данным может требовать большого количества времени, да и производительность всей системы может в таком случае упасть. Например, требуется отслеживать клиентские продажи за определенный промежуток по заданной группе или по всем пользователям разом. Решающий эту задачу запрос в «боевой» базе перелопатит ее полностью, прежде чем подобный отчет будет сформирован. Нетрудно представить, насколько медленнее все будет работать, если такие отчеты будут нужны ежедневно.
Предварительные вычисления часто запрашиваемых значений. Всегда есть потребность держать наиболее часто запрашиваемые значения наготове для регулярных расчетов, а не создавать их заново, генерируя их каждый раз в реальном времени.
В запросах к полностью нормализованной базе нередко приходится соединять до десятка, а то и больше, таблиц. А каждое соединение — операция весьма ресурсоемкая. Как следствие, такие запросы кушают ресурсы сервера и выполняются медленно. В такой ситуации может помочь:
денормализация путем сокращения количества таблиц. Лучше объединять в одну несколько таблиц, имеющих небольшой размер, содержащих редко изменяемую (как часто говорят, условно-постоянную, или нормативно-справочную) информацию, причем информацию, по смыслу тесно связанную между собой. В общем случае, если в большом количестве запросов требуется объединять более пяти или шести таблиц, следует рассмотреть вариант денормализации базы данных.
Денормализация путём ввода дополнительного поля в одну из таблиц. При этом появляется избыточность данных, требуются дополнительные действия для сохранения целостности БД.

Партицирование Таблиц

ускорение выборки данных;
ускорение вставки данных;
упрощение удаления старых данных;
упрощение обслуживания таблицы.
Следует помнить, что партицирование — не панацея. Как и с любым другим инструментом, его применение не означает автоматически, что, например, проблема ускорения выборки или вставки данных будет решена. Результат сильно зависит от структуры таблицы, используемых индексов, критерия партицирования, размера партиций и прочих условий. Без ключа будет дольше выборка данных.

Оптимистичная и пессимистичная блокировка


select from table ​Пессимистичная блокировка
При пессимистичной блокировке для записи ставится эксклюзивная блокировка на уровне базы данных, запрещая таким образом доступ к данным из других транзакций. Существует несколько видов пессимистичных блокировок:
блокировка при чтении
блокировка при записи
При блокировке при чтении запись блокируется когда она запрашивается из базы данных. Недостаток метода в том, что таким образом можно заблокировать даже те данные, которые не изменяются в рамках текущей транзакции.
При блокировке при записи блокировка даных происходит при их обновлении в базе данных до конца текущей транзакции.

Transactions

последовательность действий которые обязаны все вместе завершиться успешно или откатиться.

Виды блокировок

База данных в зависимости от выставленного уровня изоляции и операции, которая должна быть выполнена, может выставлять блокировки разных видов. К самым популярным видам блокировок относятся Shared и Exclusive lock. Для простоты можно считать, что Shared lock является блокировкой на запись. Она накладывается в случае выполнения какого-нибудь select'а, причем одна запись может быть вычитана несколькими транзакциями параллельно. Exclusive lock выставляется в том случае, если осуществляется update или delete некоторой строчки. При таком виде блокировки чтение этой строчки осуществить невозможно.

ACID – свойства которыми должны обладать transactions

Atomicity - либо весь набор действий в транзакции, либо ничего.
Consistency - каждая успешная транзакция всегда фиксирует только разрешаемые результаты. Это гарантирует, что все ограничения будут соблюдены (например, NOT NULL), иначе — транзакция откатится. Транзакция не должна ничего сломать.
Isolation - транзакция не аффектит другие. Не прошедшая транзакция никак не влияет на данные.
Durability - если транзакция выполнена,  внесенные ею изменения не отменятся из-за сбоя.

Isolation level  – уровни изоляции при параллельных транзакциях

Уровни изоляции (1-3) называются по проблемам которые они решают. Самый жесткий уровень и медленный Serializable.
Read uncommitted – чтение незафиксированных данных. Только отсутствие потерянных обновлений (ситуация, когда при одновременном изменении одного блока данных разными транзакциями одно из изменений теряется).
Read committed (default) – транзации не могут читать незакомиченные измения. Обеспечивает защиту от «грязного» чтения (чтение данных, добавленных или изменённых транзакцией, которая впоследствии откатится).
Repetable read – Решает проблему Nonrepeatable Read (ситуация, когда при повторном чтении в рамках одной транзакции ранее прочитанные данные оказываются изменёнными).
Serializable – Транзакции полностью изолируются друг от друга, каждая выполняется так, как будто параллельных транзакций не существует — защищает от фантомного чтения (ситуация, когда при повторном чтении в рамках одной транзакции одна и та же выборка дает разные множества строк).
Isolation Level
Dirty Read
Nonrepeatable Read
Phantom Read
Serialization Anomaly
1
Read uncommitted
+, not in PG
+
+
+
2
Read committed
+
+
+
3
Repeatable read
—, not in PG
+
4
Serializable
There are no rows in this table
Propagation in @Transactional Spring
REQUIRED default - если транзакция есть добавится к ней, иначе создаст новую.
REQUIRES_NEW - если транзакция есть приостановит, в любом случае создаст новую.
SUPPORTS - если транзакция есть использует ее, иначе выполнится без транзакции.
NOT_SUPPORTED - если транзакция есть приостановит и выполнится без транзакции.
MANDATORY - если транзакция есть использует ее, иначе бросает исключение.
NEVER - если транзакция есть бросает исключение.
NESTED - если транзакция есть создает сейвпоинта, если выбросится исключение, транзакция откатиться до сэйвпоинта. Если транзакции нет работает как REQUIRED.
Триггеры

SQL

Теорема CAP

В CAP говорится, что в распределенной системе возможно выбрать только 2 из 3-х свойств:
C (consistency) - согласованность. Каждое чтение даст вам самую последнюю запись.
A (availability) - доступность. Каждый узел (не упавший) всегда успешно выполняет запросы (на чтение и запись).
P (partition tolerance) - устойчивость к распределению. Даже если между узлами нет связи, они продолжают работать независимо друг от друга.
Syntaxis

Where vs Having

Во-первых, в HAVING и только в нём можно писать условия по агрегатным функциям (SUM, COUNT, MAX, MIN и т. д.). То есть если вы хотите сделать что-то вроде COUNT() > 10, то это возможно сделать только в HAVING*.
"Почему бы не оставить только HAVING?" - спросите вы. Всё кроется в том, как SQL Server выполняет запрос, в каком порядке происходит его разбор и работа с данными. WHERE выполняется до формирования групп GROUP BY. Это нужно для того, чтобы можно было оперировать как можно меньшим количеством данных и сэкономить ресурсы сервера и время пользователя.
Следующим этапом формируются группы, которые указаны в GROUP BY. После того как сформированы группы, можно накладывать условия на результаты агрегатных функций. И тут как раз наступает очередь HAVING: выполняются условия, которые вы задали.
Главное отличие HAVING от WHERE в том, что в HAVING можно наложить условия на результаты группировки, потому что порядок исполнения запроса устроен таким образом, что на этапе, когда выполняется WHERE, ещё нет групп, а HAVING выполняется уже после формирования групп.

DISTINCT --исключает повторяющиеся строки
ALL -- все данные и повторения
FROM //
WHERE //
GROUP BY //
HAVING //
ORDER BY //
ASC //
DESC //
LIMIT //
--Общая структура запроса
SELECT [DISTINCT | ALL] поля_таблиц
FROM список_таблицы
[WHERE условия_на_ограничения_строк]
[GROUP BY поля_группировки]
[HAVING условие_на_ограничение_строк_после_группировки]
[ORDER BY условие_сортировки [ASC | DESC]]
[LIMIT ограничение_количесива_записей]

Параметры оператора
image.png
image.png

Индексы

Искать записи в таблице полным перебором долго. Индексы позволяют нам исключить подмножества записей и искать только в определенном. Индексами можно представить как оглавление книги.
Типы индексов в postgres
B-tree - используется по умолчанию, можно проиндексировать любые данные, которые могут быть отсортированы, т. е. для которых применимы операции сравнения больше/меньше/равно. Ускоряет сортировку, в ORDER BY проиндексированное поле.
Найти пользователя по его email:SELECT * FROM users WHERE email='user@mail.com'
Найти товары одной из двух категорий:SELECT * FROM goods WHERE category_id = 10 OR category_id = 20
Найти количество пользователей, зарегистрировавшихся в конкретный месяц:SELECT COUNT(id) FROM users WHERE reg_date >= 01.01.2021 AND reg_date <= 31.01.2021

Триггеры

Триггер определяет операцию, которая должна выполняться при наступлении некоторого события в базе данных. Триггеры срабатывают при выполнении с таблицей команды SQL INSERT, UPDATE или DELETE. В PostgreSQL триггеры создаются на основе существующих функции, т.е. сначала командой CREATE FUNCTION определяется триггерная функция, затем на ее основе командой CREATE TRIGGER определяется собственно триггер.

План / оптимизация запроса

EXPLAIN ANALYZE
SELECT *
FROM one_million;

QUERY PLAN
___________________________________________________________
Seq Scan on one_million
(cost=0.00..18334.00 rows=1000000 width=37)
(actual time=0.015..1207.019 rows=1000000 loops=1)
Total runtime: 2320.146 ms
(2 rows)

Table 3
Document
MongoDB
1
CouchDB
2
Column
Cassandra
3
Time series
InfluxDb
4
TimesacaleDb
5
Realtime
Firebase
6
RethinkDb
7
Graph
Neo4j
8
Cache
Redis
9
Memcached
10
General
Data modelling
11
How to connect
12
Operators and constructions
13
Pros and cons
There are no rows in this table

Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.