• Что такое база данных

  • Реляционные и нереляционные базы данных

  • SQL

  • Транзакций

  • ACID

  • Уровни изоляций

  • Индексы

  • NoSql

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

Что такое база данных

База данных является системой в которой хранятся данные, данные могут быть разные по своей сути и хранится в разных форматах, и для каждого из них существует своя СУБД(Система управления базами данных) подходящая под те или иные запросы к системе.

Помимо хранения база данных так же предоставляет возможности по добавлению, изменению, удалению и получению данных, разные СУБД подходят к этим операциям по разному, но если говорить глобально то у нас есть два основных типа, это реляционные и нереляционные базы данных, предлагаю поговорить о них по подробнее

Реляционные и нереляционные базы данных

Как я уже сказал, глобально все базы данных делятся на два типа это реляционные и нереляционные, разберем каждый из этих типов более подробно:

Реляционные:

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

  • Лучше подходят для хранения упорядоченных текстовых данных

  • Вторая особенность это язык SQL, каждая реляционная СУБД работает через посредством этого языка, он является декларативным языком программирования который и позволяет нам совершать наши операций с данными

  • Каждая реляционная база данных поддерживает такую вещь как индексы, к ним мы вернемся позже, а пока лишь скажу что они нужны для ускорения поиска

  • ACID, это акроним который говорит нам о том как нам стоит подходить к проектированию нашей бд

  • В реляционных бд есть такая вещь как уровни изоляции, которые позволяют нам безопасно производить операций с данными

Нереляционные:

  • Нереляционные базы данных в отличий от реляционных не имеют единой общепринятой структуры, они могут хранить данные в любом виде и любом формате и никто им этого не запретит

  • Так же язык запросов, у каждой нереляционки он может быть свой и нет единого стандарта, плюс нереляционки не всегда но зачастую не поддерживают операций объединения, например Cassandra

  • Подходят для хранения данных в любом виде, а так же лучше работают с неупорядоченными данными

SQL

SQL - это язык запросов, применяемый в реляционных СУБД, с его помощью можно полностью манипулировать вашей базой данных, по своей сути sql это декларативный язык программирования и как и с любым другим ЯП, есть профессионалы, которые занимаются разработкой на нем.

Основные команды SQL:

CREATE - используется для создания чего либо, будь-то базы данных, или таблицы

UPDATE - используется для изменения каких-либо данных

DELETE - применяем для удаления

INSERT - служит для ставки данных

SELECT - Данная команда служит для поиска данных внутри нашей бд

Помимо данных команд SQL так же поддерживает операций объединения, такие как join, причем у нас есть несколько типов join-ов, сейчас рассмотрим их чуть более внимательно

  • inner join - выводит из таблиц только те данные которые подходят условию (в PostgreSQL который на данный момент является самой популярной реляционной субд, является дефолтным, а следовательно если не будет явно указан тип join в условий, то будет применен именно он)

  • left join - второй по популярности join который выводит результаты которые соответствуют условиям и все данные из левой таблицы

  • right join - по сути работает как left join только как понятно из названия, берет все данные из правой таблицы

  • outer join - выводит все данные из левой и правой таблиц

  • cross join - наверное самый не очевидный и мало используемый join, суть в том что он создает таблицу с декартовым произведением двух таблиц со всеми возможными вариантами, поэтому если в итоговой таблице должно быть 3 записи, то он вернет 12, если 5 то 25

Транзакций

Транзакций это один из способов безопасных операций с данными, если говорить по сути, то в ядре своем транзакций содержат идею того, что мы в них можем поместить какое угодно количество операций, и если в какой-то момент одна из этих операций не сможет выполнится то все изменения будут откачены и не зафиксированы, приведу пример на postgres

BEGIN;
UPDATE accounts SET balance = balance - 100.00 WHERE name = 'Alice'; SAVEPOINT my_savepoint;
UPDATE accounts SET balance = balance + 100.00 WHERE name = 'Wally'; COMMIT;

В данном примере мы видим, что любая транзакция начинается с команды BEGIN, после чего идут стандартные sql операций, а в конце идет команда COMMIT . Идея заключается в том что если во время выполнения данных команд произойдет какая-то ошибка, то все предыдущие изменения не сохранятся

Так же есть возможность откатить транзакцию командой ROLLBACK

ACID

ACID - это акроним, каждая буква которого говорит нам, каким именно способом нам надо подходить к построению нашей БД. Каждая буква несет определенное правило, соблюдение которого является в наше время обязательным для построения надежной базы

A - атомарность, говорит о том что все транзакций в бд должны быть атомарны, то есть не должны зависеть друг от друга

C - консистентность, данные внутри нашей базы должны быть консистентны, то есть не должно быть такого что сохранилась только часть наших данных, скажем у нас есть 3 колонки внутри таблицы, пользователь решил зарегистрироваться но что-то произошло и в результате сохранилось только ID и имя но не сохранилась почта, для этого как раз мы и должны применять транзакций

I - изолированность, все операций внутри нашей бд должны выполнятся изолированно, одна операция никак не должна задевать другую, для этого мы применяем уровни изоляций

D - надежность, означает что если пользователь получил подтверждение об успешном выполнении какой-то операций, то эта операция 100% должна быть выполнена

Уровни изоляции

Уровни изоляции эта та вещь, благодаря которой мы можем избежать грязного и фантомного чтения данных, в классическом варианте выделяют 4 традиционных уровня изоляции, но в postgres поддерживает только 3 из них.

  1. Uncommited read - первый уровень изоляции, который позволяет читать любые данные из бд, его главная проблема в том что сразу после чтения данных, может завершится какая-то транзакция и следовательно, пользователь получит не актуальные данные. Именно этот уровень изоляции не поддерживается в postgres в документаций это явно указано и даже если пользователь попытается явно его выполнить, postgres это проигнорирует и автоматически выполнит следующий уровень

  2. Commited read - данный уровень изоляции отличается от первого тем что читает только те данные по которым были закомичены транзакций, в целом он уже в большинстве случаев позволяет избежать проблемы грязного чтения, однако транзакция всегда может быть откачена

  3. Repeateble read - В отличий от первых двух, как следует из названия читает данные два раза, позволяет избежать проблемы грязного чтения, однако не может обезопасить нас от фантомного чтения, это когда транзакция в ходе выполнения выбирает несколько строк по одним и тем же критериям, но при этом приходит к разному результату

  4. Serializable - при данном уровне изоляции, все транзакций выполняются синхронно, друг за другом, вследствие чего мы избегаем всех выше перечисленных проблем, но платим за э��о гораздо более медленной скоростью работы нашей бд

Индексы

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

Существует несколько основных типов индексов, первый из которых это B-tree

B-Tree - это сбалансированное дерево, самый популярный на данный момент индекс, у которого логарифмическая скорость поиска, а так же он поддерживает операций неравенства, однако важно помнить что индекс работает хорошо до первого неравенства в условий, после чего начинается поиск через стандартный sequesn scan или же перебор, так же является дефолтным в postgres и если при созданий индекса явно не указать какой индекс мы хотим ��спользовать, то автоматически создастся именно он

Скорость у данного индекса достигается как раз за счет хорошей балансировки дерева, из-за чего на каждом уровне этого дерева у нас отрезается достаточно большая часть данных, из-за чего конечная скорость поиска становится O(log^n). Однако важно помнить, что у искомых данных должна быть высокая селективность, другими словами чем больше уникальных данных для поиска в условий тем быстрее и лучше будут работать индексы, а если мы скажем будем делать поиск по полю у которого значение может быть либо 0 либо 1, то в таких случаях наша база может даже деградировать по скорости, так-как ей придется опрашивать не только саму таблицу но и индекс, далее важно помнить следующее, чем меньше данных будет возвращаться в конечном итоге тем лучше покажет себя индекс, поэтому если ваша бд должна возвращать скажем 1мл записей, скорее всего индексы вам не помогут.

Следующий индекс который мы разберем это Hash, в отличий от b-tree он является колоночным индексом и поддерживает только операцию равенства, однако в ряде случаев за счет того что поиск по хэшу у нас является в лучшем случае O(1) , а в худшем O(n), может на определенных условиях показывать себя лучше чем b-tree, однако перед его использованием необходимо все взвесить, ибо накосячить с ним гораздо легче

Далее идут специализированные индексы, такие как GiST, GIN и SP-GiST, не будем на них подробно останавливаться, так-как эти индексы являются достаточно редкими и люди которые их используют, хорошо понимают как работают деревья, графы и тд

Индексы действительно способны повысить скоро��ть поиска данных, однако несут несколько недостатков, первый из которых это то что у нас замедлятся все остальные операций, так-как теперь помимо внесения изменений в нашу основную таблицу, нам так-же необходимо внести изменения и в индексы, что естественно отнимает время. Так же, индексы существуют не в вакууме, а следовательно как и все в нашем мире тоже потребляют место на жестком диске, так же данные должны обладать высокой селективностью для избежания деградации нашей БД. Если же нам необходимо создать индекс на данные с низкой селективностью, нам могут помочь частичные индексы которые работают на конкретных колонках.

NoSql

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

Нереляционки как я уже говорил, лучше подходят если мы храним данные в неупорядоченном виде или же данные не в текстовом формате.

Самыми популярными NoSql базами на данный момент являются:

  • MongoDB - хранит данные в bson формате, по своей сути напоминает json, однако позволяет хранить данные в date формате, а так же бинарные файлы

  • Redis - самая популярная бд используемая для кэша, хранит данные в оперативной памяти, за счет чего обеспечивает быстрый доступ к данным, но потерять из нее данные гораздо легче чем из обычной базы

  • Clickhouse - разработана Яндексом и служит для хранения информации о действиях пользователя на сайте

  • Cassandra - используется для хранения больших данных, за счет высокой скорости и легкости масштабирования

Итог

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