# #22: Архитектура баз данных: компоненты и классификация

- Выпуск: 22 · Сезон: 1 · Дата: 2023-06-19 · Длительность: 24:10
- Страница: https://apkhmv.xyz/podcast/episode-22/
- Аудио: https://traffic.libsyn.com/secure/173caf0e-b8e8-4056-8a73-2d60d94118ef/22_Database_Architecture.mp3
- Ведущий: Александр Пахомов (https://apkhmv.xyz/people/apkhmv/index.md) · Гости: нет
- Темы: базы данных, архитектура СУБД, OLAP и OLTP, колоночные хранилища, подсистема хранения
- Расшифровка: draft · Источник: речь участников выпуска, цитируется как есть

## Кратко

Второй выпуск сезона про базы данных. Через развёрнутую аналогию с сортировочным складом Александр Пахомов разбирает верхнеуровневую архитектуру почти любой СУБД — транспортный уровень, обработчик запросов с оптимизатором, подсистему выполнения и подсистему хранилища (диспетчеры транзакций, блокировок, буфера, восстановления и средства доступа), — а затем классифицирует базы данных по методам хранения: OLTP против OLAP, in-memory против дисковых, строковые против колоночных. В финале — идея композируемости: современные СУБД собираются из переиспользуемых блоков, но абстракции между слоями неизбежно текут ради скорости.

## Главное

- Почти любая СУБД состоит из четырёх слоёв: транспортный уровень, обработчик запросов (парсер + оптимизатор), подсистема выполнения и подсистема хранилища.
- Транспортный уровень двусторонний: одна подсистема общается с клиентом, другая — между нодами кластера, и они могут переиспользовать общий код.
- Обработчик запросов сперва парсит и валидирует запрос (включая проверку доступа к объектам), а затем оптимизатор строит план запроса — дерево исполнения, которое видно через `EXPLAIN`.
- Подсистема выполнения бывает локальной (`JOIN`-ы, сортировки, агрегации, чтение и запись данных) и удалённой (передать запрос или его часть на другую ноду).
- Подсистема хранилища — самая сложная: диспетчер транзакций, диспетчер блокировок, средства доступа (`LSM`- или `B-Tree`-деревья), диспетчер буфера и диспетчер восстановления.
- Большинство СУБД не полагаются на виртуальную память ОС для кэширования страниц, а реализуют собственный диспетчер буфера — это осознанное решение.
- OLTP-базы (Postgres, Oracle) оптимизированы под частые одиночные чтения и записи и обычно строковые; OLAP-базы оптимизированы под редкие тяжёлые аналитические запросы и обычно колоночные.
- Колоночное хранение выигрывает на агрегатах по одному полю (векторные `SIMD`-инструкции, лучшее сжатие однотипных данных), но проигрывает строковому на выборке всех полей одной записи.

## Главы

- [00:20](https://apkhmv.xyz/podcast/episode-22/?t=20) Вступление: компоненты и классификация БД
- [01:10](https://apkhmv.xyz/podcast/episode-22/?t=70) Аналогия со складом
- [04:04](https://apkhmv.xyz/podcast/episode-22/?t=244) Склад как база данных: расшифровка аналогии
- [05:53](https://apkhmv.xyz/podcast/episode-22/?t=353) Четыре слоя и транспортный уровень
- [06:23](https://apkhmv.xyz/podcast/episode-22/?t=383) Обработчик запросов: парсер и оптимизатор
- [08:04](https://apkhmv.xyz/podcast/episode-22/?t=484) Подсистема выполнения: локальная и удалённая
- [08:44](https://apkhmv.xyz/podcast/episode-22/?t=524) Подсистема хранилища и её диспетчеры
- [11:39](https://apkhmv.xyz/podcast/episode-22/?t=699) Чем различаются БД: OLTP и OLAP
- [14:38](https://apkhmv.xyz/podcast/episode-22/?t=878) In-memory против дисковых баз данных
- [16:07](https://apkhmv.xyz/podcast/episode-22/?t=967) Колоночные против строковых хранилищ
- [20:20](https://apkhmv.xyz/podcast/episode-22/?t=1220) Композируемость: переиспользование блоков

## Ссылки

- Нет.

## Похожие выпуски


- [#16: Спэшл: RBAC](https://apkhmv.xyz/podcast/episode-16/index.md) — общие темы: базы данных
- [#21: Введение в базы данных: История и SQL](https://apkhmv.xyz/podcast/episode-21/index.md) — общие темы: базы данных
- [#23: SSD и HDD: устройство дисков и слотированные страницы](https://apkhmv.xyz/podcast/episode-23/index.md) — общие темы: базы данных
- [#24: Лучшая структура данных: B-tree, B+tree](https://apkhmv.xyz/podcast/episode-24/index.md) — общие темы: базы данных

## Расшифровка


**[00:20]** Здорово! Меня зовут Саша Пахомов, и я инженер, который любит своё дело. Вы слушаете подкаст, в котором разработчик современной базы данных изучает то, как они работают, и делится знаниями со слушателями. В прошлом выпуске мы изучали историю баз данных и немного освежили знания по языку запросов SQL. Сегодня поговорим о том, из каких основных компонентов устроена почти любая база данных: это транспортный уровень, оптимизаторы запросов, система выполнения и система хранения. А ещё рассмотрим, чем базы данных могут различаться между собой — OLAP или OLTP, in-memory или персистентные, строковые или колоночные. Мы погружаемся в мир баз данных. Поехали!

**[01:10]** Представьте, что вы приехали на склад. Это такой снаружи ничем не примечательный ангар — он выглядит как наполовину закопанный в землю, лежащий на боку цилиндр. К ангару стоит очередь из грузовиков, которые привозят и отвозят посылки. Это всё, что мы видим снаружи. Давайте заглянем внутрь и посмотрим на устройство склада. Первое, что мы видим, — это грузчики, которые забирают посылки из грузовиков и несут их на распределительную ленту. Дальше вдоль ленты стоят роботы с камерами: камеры позволяют им определить тип посылки. Это может быть большая коробка с велосипедом, стопка писем или кроссовки. Под каждый тип посылки существует своя лента, и роботы раскладывают их на соответствующие ленты. Это процесс сортировки посылок.

**[01:50]** В конце каждой ленты стоят погрузочные машины, которые ездят туда-сюда и отвозят посылки на специальные высоченные стеллажи с полками. Но делают они это не по одной посылке за раз, а сразу нагружают целую стопку — так быстрее. Некоторые машинки едут быстро в самый конец полки и складывают пачки посылок одна за одной. Другие находят специальные места в середине полки, пододвигают соседние посылки и вставляют туда ещё одну. Таким образом на одной полке все посылки отсортированы по дате доставки, и погрузка на отправку будет гораздо быстрее. Пока оператор машины стоит возле полки, остальные выстраиваются в очередь и ждут — это плата за скорость отправки.

**[02:29]** Если мы посмотрим, как организованы стеллажи, то увидим, что ближайшие к выходу — те, на которых хранятся короткосрочные посылки: их погрузят в ближайшее время, и нет смысла увозить их далеко. А те, которые будут лежать на складе долго, отправляются в самый конец. Некоторые из коробок, что мы видим близко, иногда перемещаются подальше, потому что место на ближайшей полке ограничено, и посылка с самым коротким временем хранения вытесняет остальные. Сами по себе стеллажи тоже отличаются друг от друга. Одни хранят посылки одного размера в едином боксе — так экономится место, ведь одинаковые коробки не оставляют пустого пространства между собой; к тому же погрузчик может взять весь бокс целиком, а не возить посылки по одной. А рядом стоит стеллаж, на котором нет боксов и разные посылки лежат вперемешку, зато у всех них один и тот же получатель — и оператор может взять их пачкой и отвезти за раз. Хотя это не так эффективно с точки зрения перевозки, зато всё за один раз и для одного получателя.

**[03:24]** Отводим взгляд от стеллажей и полок и видим, что одна из машинок поехала сразу к выходу. Она кладёт посылки в грузовик, на котором написано имя другого склада: там хранят велосипеды, а на нашем складе под них нет подходящих полок. Всё это выглядит как хаос снаружи, но на самом деле склад — это хорошо отлаженный единый организм.

**[04:04]** Думаю, многие из вас уже догадались, к чему это было. Наш воображаемый склад — это то, как устроено большинство баз данных. Давайте пробежимся по основным блокам, держа в голове представление о складе. Аналогий будет много. Итак, грузовики между складами — это транспортный уровень: он отвечает за коммуникацию и снаружи базы данных, с её пользователями, и внутри, то есть между нодами (ангарами). Посылки — это наши данные. Люди и машинки внутри — это процессор, который работает на базе данных. Грузовики — это процессы или потоки со своей логикой, подсистема локального исполнения. Сортирующие роботы — это анализаторы запросов: они первыми парсят входящий запрос и принимают решение, куда его направить, а невалидные запросы просто отбрасывают. А тот факт, что машинки возят товары не по одному, а пачками с определённых лент, — это заслуга оптимизатора запросов.

**[04:42]** Стеллажи — это файлы с данными, а полки — это массивы байтов. Те стеллажи, что хранят посылки в единых боксах, очень похожи на колоночные хранилища, а те, что хранят посылки одного получателя, — на строковые хранилища типа Postgres. Когда оператор кладёт все посылки в конец стеллажа, это хранилище, оптимизированное под быструю запись, — его ещё иногда называют логом: туда мы быстро пишем, но найти нужную посылку там сложнее. А вот в отсортированном по дате отправки стеллаже найти посылку очень просто, но положить туда новую гораздо сложнее — так устроены отсортированные структуры данных, оптимизированные под быстрый поиск. Когда один оператор занимает часть полок на стеллаже — это блокировка: другие процессы должны ждать, даже несмотря на то, что иногда им нужно взять всего одну коробку с полки. А посылка с велосипедом, которая поехала в другой склад, раскрывает нам глаза на то, что склад на самом деле распределённый. В мире распределённых систем мы называем это кластером, а склад, который мы рассматривали, — это нода внутри кластера. Такая вот аналогия — думаю, некоторые из вас смогут её оценить.

**[05:53]** Если говорить уже без аналогии, то есть на техническом инженерном языке, то в целом мы имеем следующую архитектуру большинства баз данных: транспортный уровень, уровень обработчиков запросов, уровень подсистемы исполнения и подсистема хранилища. Транспортный уровень как бы делится на два. Первая — подсистема коммуникации внутри кластера, то есть то, как ноды между собой общаются. Вторая — подсистема коммуникации с клиентом. Это две разные транспортные системы, но они могут шерить между собой общий код или даже использовать одни и те же методы.

**[06:23]** Дальше первый, кто начинает обрабатывать запрос и встречается с ним непосредственно, — это обработчик запросов. Там тоже есть разделение: синтаксический анализатор запросов и оптимизатор запросов. Анализатор, во-первых, парсит запрос на том языке, на котором он пришёл, — скорее всего, это будет SQL, как мы уже поняли из прошлого выпуска. Он его валидирует: там могут быть какие-то невалидные конструкции. А если всё валидно и нормально, и такие объекты действительно есть, то он может, например, проверить доступ к объектам: если у пользователя нет доступа к какой-то таблице, из которой читает запрос, то запрос на этом уровне уже обрубится. Кстати, если вам интересно, как вообще устроена система ролей, юзеров и пермиссий, — можете послушать мой выпуск RBAC Special, я там про это всё рассказываю.

**[07:10]** Итак, синтаксический анализатор запросов делает эту работу и передаёт её оптимизатору. Оптимизатор строит своё внутреннее представление, которое называется планом запроса; вы можете его посмотреть, например, выполнив `EXPLAIN` на каком-нибудь Postgres, — и увидите, как это выглядит. Оптимизатор запросов — вообще сложная штука, и мы их обязательно рассмотрим в следующих выпусках. Но чтобы иметь представление: этот план — некое дерево исполнения. Оптимизатор отсекает ненужное, может делать эквивалентные преобразования — например, перевернуть дерево, выстроить индексы. У него есть статистика, он знает мощность (cardinality) индексов и может понять, когда какой индекс лучше использовать — хэш-индекс или другой. Всю эту работу он выполняет и в конце концов передаёт оптимизированное представление запроса подсистеме выполнения.

**[08:04]** Подсистема выполнения тоже может быть двух типов — локальной и удалённой. Локальная представляет наибольший интерес, потому что именно там происходят все эти джойны, сортировки, агрегации: вычитать данные, положить данные, посчитать — вся эта работа происходит там. А удалённое выполнение — это просто запрос на другую ноду. Причём тут тоже возможны варианты: мы можем передать туда запрос и сказать «дай мне данные, я сейчас посчитаю локально», а можем передать часть запроса, попросить посчитать удалённо и получить уже готовый результат. Это два разных подхода, и мы их все рассмотрим. Вот такая система выполнения.

**[08:44]** И самое низкое, самое ближайшее к железу, к дискам, — это подсистема хранилища. Внутри себя она устроена, наверное, сложнее всего; может, по сложности с ней и способны посоревноваться оптимизаторы запросов, но всё-таки подсистема хранилища — отдельная обособленная штука. Она состоит, например, из диспетчера транзакций, диспетчера блокировок, средств доступа, диспетчера буфера и диспетчера восстановления. Каждая из этих систем выполняет вполне определённую задачу. Диспетчер транзакций, например, следит за тем, чтобы все операции — чтения, записи — были согласованы в рамках одной транзакции; все эти уровни изоляции транзакций как раз лежат на нём. Делает он это с помощью диспетчера блокировок, который, когда нужно, некоторые записи или некоторые страницы в памяти просто блокирует, никому не даёт прочитать и предоставляет эксклюзивный доступ какому-то одному процессу, какому-то запросу.

**[09:36]** Средства доступа тоже бывают разные — например, это могут быть LSM-деревья или какие-то B-Tree-деревья. От этого зависит, как быстро будет выполнен запрос и как быстро будет выполнена вставка; как раз средства доступа за это и отвечают. Также есть буферизация: некоторые страницы буферизируются в памяти, чтобы не бегать каждый раз на диск, и за это отвечает отдельная подсистема — у каждой базы данных она своя. Кто-то может сказать, что за нас это может сделать операционная система с помощью виртуальной памяти, но большинство баз данных виртуальную память не используют — это плохая идея. Возможно, мы и про это поговорим, как оно всё устроено; сейчас же просто рассматриваем верхний уровень. Это диспетчер буферизации. И ещё есть диспетчер восстановления. Это на случай, когда что-то пойдёт не так: например, выдернут электричество, моргнёт сеть или просто случится out of memory — короче, приложение внезапно упадёт. Тогда, когда мы будем стартовать после этого нежданного падения, диспетчер восстановления начнёт работать: какие-то транзакции откатит, какие-то доведёт до валидного состояния, какие-то записи отвергнет и скажет, что они были неудачными, что-то вычитает из логов. В общем, у него там тоже огромная работа, которую мы рассмотрим в дальнейшем.

**[10:54]** Вот так плюс-минус выглядит верхнеуровневая архитектура среднего по больнице, среднего по рынку продукта — базы данных. Также, если смотреть на детали, на какие-то конкретные вещи, — их тоже реализует большинство баз данных. Например, это JDBC-доступ, это ODBC. У большинства современных баз данных есть какой-то REST. Есть CLI — я, кстати, тоже писал REST и CLI для баз данных. Есть нативные клиенты языков программирования: если вы хотите подключить себе библиотечку в Java и работать напрямую, красиво и компилируемо, вместо того чтобы писать запросы строками и пользоваться JDBC, — такая возможность тоже есть, некоторые базы данных её предоставляют. То есть это уже конкретные реализации конкретных методов доступа.

**[11:39]** Но помимо этой общей архитектуры, этих общих вещей, которые мы рассмотрели, базы данных, конечно же, между собой различаются. Иначе какая вообще была бы у разработчиков баз данных мотивация разрабатывать такое их количество? В основном различия — это методы хранения данных и методы распределения. Если говорить про методы хранения, то, как правило, начинают с OLTP и OLAP. Про это я, наверное, тоже запишу отдельный выпуск — или в рамках какого-то выпуска мы глубоко рассмотрим, что это такое. Но если коротко, то OLTP — это Online Transactional Processing, а OLAP — Online Analytical Processing. «Online» отсюда можно вообще убрать, да и «Processing» тоже — оставить только Transactional и Analytical: по сути, различаются они именно этим.

**[12:27]** Transactional — это, например, какой-нибудь Postgres. Он хорошо работает транзакционно, то есть хорошо делает много одиночных чтений и записей. Возьмём банально какой-нибудь интернет-магазин с товарами, пользователями, корзинами. Там нет ничего такого, что можно было бы аналитически запрашивать, — если мы говорим именно про веб-сайт (какие-то системы рекомендаций и прочее не берём). Вот берём классический интернет-магазин: нам нужно уметь создать пользователя, удалить пользователя, изменить у него какие-то поля. У него есть список полей, десяток штук — адрес, e-mail, имя, номер телефона, способ оплаты, — какие-то стандартные, банальные вещи. И паттерн доступа к бэкенду такой: дай мне вот этого пользователя, дай мне список его корзин, дай мне его историю, дай мне вот это. То есть всё такое одиночное — поэтому и называется transactional. Под одиночные, но частые запросы и оптимизированы OLTP-базы данных: Postgres, Oracle, например.

**[13:28]** А вот OLAP, или аналитические базы данных, оптимизированы под другое — под большие, действительно аналитические запросы. Это когда какой-нибудь аналитик или продакт сидит и не через основную морду веб-сайта смотрит товары, а подключается с другого края, через свою BI-систему, и думает: «А за февраль у нас покупок по вот этому товару в среднем насколько больше или меньше, чем за январь?» Такой запрос уже сам по себе формулирует аналитику, но под ним лежат данные как минимум за два месяца, по всем — то есть огромное количество данных, если у нас большой интернет-магазин. И чтобы с этим справиться, нужна как раз заточенная под такие большие запросы аналитическая база данных. Ей не обязательно обеспечивать транзакционность такого запроса — вообще не нужно её обеспечивать. И скорость ответа тоже не так критична: аналитик в целом может подождать минуту или секунд тридцать, а вот пользователь столько ждать не будет. Поэтому аналитические базы данных заточены под такой паттерн использования. В этом и есть различие OLTP и OLAP.

**[14:38]** Помимо этого банального различия, можно, например, разделять базы данных на in-memory и персистентные. Вообще in-memory баз данных не так много, но они принципиально отличаются тем, как организуют у себя внутри, что есть первичные данные, а что — вторичные. Ведь in-memory базы данных тоже часто сбрасывают данные на диск, чтобы после рестарта можно было их подтянуть. А дисковые базы данных, наоборот, кэшируют большое количество данных к себе в память, чтобы работать быстро. Так вот, разница между ними в том, что дисковые в первую очередь пишут на диск, и источник правды для них — это диск: если они сказали, что записали, и транзакция отработала, то данные точно будут на диске. А потом это дисковое состояние кэшируется — например, диспетчером буферизации или ещё какой-то системой кэширования, — чтобы работать быстро. Но в первую очередь всё лежит на диске.

**[15:31]** А in-memory базы данных, наоборот, всё сначала хранят в памяти, а потом какой-то асинхронный, неблокирующий процесс скидывает состояние на диск, чтобы в случае перезапуска поднять его и продолжить работать дальше. Тут очевидный минус: если in-memory база данных сказала, что запись прошла, и тут же закешировала её в памяти, а асинхронная подсистема не смогла записать это на диск, — то мы данные потеряем. Есть методы обхода и так далее, но основное концептуальное отличие между дисковыми и in-memory системами заключается именно в этом.

**[16:07]** Ещё одно популярное различие — колоночные против строковых баз данных. На самом деле, большинство аналитических баз данных, на мой взгляд, — это колоночные базы данных, а большинство транзакционных — строковые. То есть мир OLTP — это строковое хранилище, а мир OLAP — колоночное. Естественно, есть не то чтобы исключения — просто это не золотое правило. Могут быть и совмещённые базы данных, такие как HTAP (Hybrid Transactional Analytical Processing), которые сочетают в себе и то, и другое: там, естественно, идёт сочетание колоночного и строкового подходов. Вообще всё это не так однозначно и просто, но колоночные и строковые базы данных люди, как правило, между собой различают.

**[16:50]** А различие тут как раз в том, что строковые базы данных хранят данные построчно: вот эта строка так и представлена, как строка в табличке. Представим: имя, фамилия, год рождения и, например, e-mail — вот эта строка единым массивом хранится на диске, за ней идёт следующая строка, за ней ещё, — такое вот строчное хранилище. Преимущество в том, что если мы хотим вычитать всю информацию по одному пользователю, то идём по смещению в файле, забираем эту запись — и вот он, кусок памяти, в котором лежат все данные про нашего пользователя. Одно чтение, одна запись — супер. А вот если мы хотим выполнить аналитический запрос — например, посчитать количество уникальных семёрок в номерах телефонов всех пользователей, — то нам нужны только номера телефонов. Но считать только номера телефонов при такой системе хранения мы не можем: мы будем считывать всех пользователей — с именами, фамилиями, ещё кучей информации, которая лежит рядом. Мы всё это считаем, потом возьмём оттуда одно поле и уже по нему пойдём считать. Это накладные расходы на аналитические запросы. То есть строковые базы данных не так хороши, если речь про аналитику.

**[17:58]** Зато у строковых баз данных есть так называемая пространственная локальность. Если мы считали, например, имя пользователя, то с высокой вероятностью нам понадобится и его фамилия — а она будет тут же рядом, в той же странице. Про постраничную организацию, про кортежи (tuples), про слотированные страницы поговорим в следующем выпуске; пока просто «что-то там есть». Строковые базы данных кэшируют это всё вместе, поэтому если мы с одним пользователем делаем много операций, то данные, скорее всего, будут рядом. Вот эта пространственная локальность — преимущество строковых баз данных.

**[18:28]** В свою очередь, колоночные базы данных отлично подходят для тех самых агрегатов по каким-то одним полям. Потому что хранят они уже не одну строку — имя, фамилия, телефон, e-mail, — а имя, имя, имя, имя, потом фамилия, фамилия, фамилия, потом телефон, телефон, телефон. Ну, вы поняли: они просто делают пивот такой таблицы и хранят её совершенно по-другому. Преимущество в том, что если мы захотим посчитать все семёрки в номерах телефонов, то просто берём кусок памяти со всеми телефонами и гоним на него запрос. Помимо этого, все эти номера телефонов имеют один и тот же тип данных — а это очень хорошо сочетается с оптимизацией выполнения. Мы можем применять такие штуки, как векторные инструкции процессора: за одну инструкцию выполнять много операций, если они однотипные, — и как раз для такого хранения это идеально подходит. Также мы можем очень хорошо делать компакшн, потому что один и тот же тип данных, лежащий последовательно друг за другом, хорошо ложится на алгоритмы сжатия: они очень хорошо работают, когда одинаковые типы данных лежат рядом, — их можно сжать проще. Про это мы тоже поговорим дальше, но такое преимущество у колоночных баз данных есть.

**[19:39]** Недостатки у этого подхода, естественно, тоже есть. Если мы захотим прочитать по одному пользователю много данных — например, я хочу имя, фамилию и e-mail, — то подсистеме нужно пойти в три места и вычитать по одному и тому же оффсету (а возможно, и не оффсету — это зависит) по одному кусочку данных: из имён взять третий, из номеров — третий, из e-mail — третий. То есть три действия, чтобы вычитать информацию про одного пользователя, — в то время как в строковых базах данных мы просто идём и вычитываем всё за один раз. Поэтому аналитические базы данных не так хорошо подходят под такие паттерны доступа. То есть одни хороши в одном, другие — в другом.

**[20:20]** Позвольте мне немного вернуться к аналогии со складом и выразить такую мысль. Мы же знаем, что склады, хоть и могут быть по-разному организованы, снаружи имеют какие-то общие процессы и переиспользуют одинаковые штуки. То есть на разных складах — на складе Amazon, Azure и так далее — полки, возможно, будут одни и те же, от одного и того же производителя. Несмотря на то что работают они по-разному, какие-то вещи они переиспользуют: сортировочного робота, подавальщик лент, грузовики, все эти машинки. То есть у каждого склада нет собственных, эксклюзивных полок — ну, у каких-то есть узкозаточенные, но большинство заказывают одни и те же, просто различают их по типу. Это облегчает процесс постройки нового склада и вообще работу — операторам тоже проще, потому что это уже знакомые вещи.

**[21:12]** В базах данных всё то же самое. Раньше каждая база данных делала свой полностью проприетарный формат хранения — ну и сейчас такие есть, свои инхаус-разработки, — и переиспользовать это было практически невозможно. Но потом разработчики баз данных поняли, что во многих местах они по сути делают одно и то же: подсистема хранения, диспетчеры транзакций, подсистема выполнения, обработчики запросов, анализаторы запросов. Они всё это пишут, тратят огромное количество ресурсов, допускают баги и ошибки — в то время как можно вынести это в отдельные продукты, в отдельные библиотеки и переиспользовать между собой. Ну давайте честно: писать парсинг SQL самому с нуля — сомнительная затея, когда на рынке уже есть готовые парсеры, которые можно просто взять и использовать. Так вот, современные базы данных так и делают: берут готовые кусочки и собирают из них ту базу данных, ту конфигурацию, которая им нужна и выгодна.

**[22:12]** Но тут не стоит обольщаться, ведь переиспользование не такое простое, как может показаться на первый взгляд. Вот вы, например, если вы бэкендер, представляете это так: да, я могу взять библиотеку парсинга JSON — какой-нибудь ObjectMapper, — заиспользовать его, потом взять Jackson, потом ещё какой-то другой; то есть я могу их вот так менять, жонглировать ими, и в целом, если код хорошо написан, буду делать это без особых проблем. А вот в базе данных проблемы возникают часто, потому что там постоянно текут абстракции. Чтобы написать оптимальный, оптимизированный код, абстракция должна протечь: мы не можем на верхнем уровне так абстрагироваться от подсистемы хранения, чтобы не делать про неё каких-то ассампшенов. То есть эти слои не так идеально изолированы между собой, как в каком-нибудь стандартном бэкенде. Где-то протечка всё-таки есть, и она необходима — иначе без неё не было бы такого быстрого выполнения. Это просто плата за то, что базы данных — продукты, которые должны работать быстро, оптимально и не тормозить. Поэтому переиспользование возможно, и оно происходит, но оно не такое простое, как может показаться на первый взгляд.

**[23:23]** На этом мы завершаем верхнеуровневый обзор архитектуры баз данных. В следующем выпуске разберёмся с тем, как устроена память у современных компьютеров и какие абстракции инженеры используют, чтобы выжать максимум из того, что имеют. Не забывайте делиться подкастом с друзьями и коллегами — давайте прокачивать себя и людей вокруг. Ну а на этом всё. Услышимся!


