Как работает SQLite
Оглавление
1. Общие сведения
SQLite — это библиотека программного обеспечения, которая преобразует запросы ввода-вывода на диске высокого уровня, генерируемые приложением, в операции ввода-вывода низкого уровня, которые могут быть выполнены операционной системой. Приложение создает запросы ввода-вывода высокого уровня, используя язык SQL. SQLite преобразует каждое высокоуровневое оператор SQL в последовательность многих запросов ввода-вывода низкого уровня (открыть файл, прочитать несколько байтов из файла, записать несколько байтов в файл и т. д.), которые выполняют работу, запрошенную SQL.
Программа-приложение может выполнять все операции ввода-вывода на диске, делая прямые вызовы к операционным системам, или используя движок хранения ключей/значений, например, Berkeley DB или RocksDB (назвать лишь два примера). Однако существуют преимущества использования интерфейса более высокого уровня, основанного на языке SQL.
SQL — это язык очень высокого уровня. Несколько строк SQL могут заменить сотни или тысячи строк процедурного кода. Таким образом, SQL уменьшает объем работы, необходимой для разработки и поддержки приложения, и тем самым помогает уменьшить количество ошибок в приложении.
SQL и SQLite являются транзакционными. Использование транзакционной системы хранения данных значительно упрощает понимание поведения приложения и создание приложений, которые являются надежными даже при наличии ошибок программного обеспечения, сбоях оборудования или отключении питания.
SQLite часто быстрее, чем прямой ввод-вывод низкого уровня. Это кажется парадоксальным. Можно ожидать, что высокоуровневый интерфейс, такой как SQLite, создаст штраф за время выполнения. И теоретически, это верно. Но на практике системы на базе SQL, такие как SQLite, проводят так много оптимизаций в фоновом режиме, что разработчик приложений никогда не успеет их создать и поддерживать, что приводит к чистому улучшению производительности систем на базе SQL.
1.1. SQLite отличается от большинства других СУБД SQL
Помимо SQLite, существует множество систем управления базами данных на основе SQL. К распространенным вариантам относятся MySQL, PostgreSQL и SQL-Server. Все эти системы используют язык SQL для взаимодействия с приложением, точно так же, как и SQLite. Но эти другие системы отличаются от SQLite по важным аспектам.
SQLite — это бессерверная библиотека программного обеспечения, в то время как другие системы основаны на клиент-серверной архитектуре. С помощью MySQL, PostgreSQL, SQL-Server и других систем приложение отправляет сообщение, содержащее SQL, на отдельный поток или процесс сервера. Этот отдельный поток или процесс выполняет запрошенные операции ввода-вывода, а затем отправляет результаты обратно в приложение. Но с SQLite нет отдельного потока или процесса. SQLite работает в том же адресном пространстве, что и приложение, используя тот же счетчик команд и хранилище кучи. SQLite не использует межпроцессное взаимодействие (IPC). Когда приложение отправляет оператор SQL в SQLite (вызывая соответствующий подпрограмму библиотеки SQLite), SQLite интерпретирует SQL в том же потоке, что и вызывающая сторона. Когда функция API SQLite возвращает значение, она не оставляет никаких фоновых задач, выполняющихся независимо от приложения.
База данных SQLite представляет собой один обычный файл на диске (с хорошо определенным форматом файла). В других системах «база данных» обычно представляет собой большое количество отдельных файлов, скрытых в малоизвестных каталогах файловой системы или даже распределенных по нескольким машинам. Но с SQLite полная база данных — это всего лишь обычный файл на диске.
2. SQL — это язык программирования
Лучший способ понять, как работают движки баз данных SQL, — рассматривать SQL как язык программирования, а не как «язык запросов». Каждый оператор SQL — это отдельная программа. Приложения создают исходные файлы программ SQL и отправляют их в движок базы данных. Движок базы данных компилирует исходный код SQL в исполняемую форму, выполняет эту исполняемую форму, а затем отправляет результат обратно приложению.
Хотя SQL является языком программирования, он отличается от других языков программирования, таких как C, Javascript, Python или Go, тем, что SQL является декларативным языком, а другие — императивными языками. Это важное различие, которое имеет последствия для проектирования компилятора, используемого для преобразования исходного текста программы в исполняемую форму. Однако эти детали не должны отвлекать от того факта, что SQL — это просто другой язык программирования.
2.1. Этапы обработки языка программирования
Все языки программирования обрабатываются в два этапа:
Преобразование исходного текста программы в исполняемую форму.
Выполнение исполняемого файла, созданного на предыдущем шаге, для выполнения желаемого действия.
Все языки программирования используют эти два основных этапа. Главное отличие заключается в формате исполняемого файла.
«Компилируемые» языки, такие как C++ и Rust, преобразуют исходный текст в машинный код, который может быть непосредственно выполнен подлежащим аппаратным обеспечением. Существуют системы баз данных SQL, которые делают то же самое с SQL — они преобразуют каждый оператор SQL напрямую в машинный код. Но этот подход нечастый и не используется SQLite.
Другие языки, такие как Java, Perl, Python и TCL, обычно преобразуют исходный текст программы в байт-код. Этот байт-код затем выполняется интерпретатором, который читает байт-код и выполняет необходимые операции. SQLite использует этот подход с байт-кодом. Если вы добавите перед оператором SQL ключевое слово «EXPLAIN» в SQLite, оно покажет вам сгенерированный байт-код, а не выполнит байт-код.
Другой подход заключается в преобразовании исходного текста программы в дерево объектов в памяти. Это дерево является «исполнимым». Интерпретатор выполняет исполняемый файл, пройдясь по дереву. Именно этот метод используется в MySQL, PostgreSQL и SQL-Server.
Конечно, не каждый язык идеально подходит к одной из вышеперечисленных категорий. Это относится как к движкам баз данных SQL, так и к более знакомым императивным языкам программирования. Javascript известен использованием гибридной модели выполнения, где код первоначально компилируется в дерево объектов, но может быть дополнительно преобразован (с использованием компиляции Just-In-Time) в более эффективный байт-код или машинный код для повышения производительности.
Формат исполняемого файла в конечном итоге является просто деталью реализации. Суть в том, что у всех языков есть этап компиляции, который преобразует программы в исполняемую форму, и этап выполнения, который выполняет скомпилированную программу.
2.2. Компиляция программ SQLite
Когда программа SQL отправляется в SQLite, первым шагом является разделение исходного текста на «токены». Токеном может быть:
- Ключевое слово языка, например «SELECT» или «UPDATE».
- Идентификатор таблицы, столбца или переменной.
- Знаки препинания, такие как «,» или «==» или «;».
- Литеральные значения: числовые или строковые константы.
- Пробелы или комментарии.
Пробелы и комментарии отбрасываются. Все остальные токены передаются в LALR(1) анализатор, который анализирует структуру входной программы и генерирует Абстрактное синтаксическое дерево (AST) для входной программы.
Анализатор передает AST генератору кода. Генератор кода — это сердце SQLite, и именно здесь происходит большая часть «магии». Генератор кода разрешает символические имена в AST — сопоставляя имена столбцов и таблиц во входном SQL с фактическими столбцами и таблицами базы данных. Генератор кода также выполняет различные преобразования над AST для его «оптимизации». Наконец, генератор кода выбирает подходящие алгоритмы для реализации операций, запрошенных AST, и создает байт-код для выполнения этих операций.
Байт-код, сгенерированный генератором кода, называется «подготовленным оператором». Преобразование исходного текста SQL в подготовленный оператор аналогично преобразованию программы C++ в машинный код с помощью вызова gcc или clang. Входной информацией является читабельный для человека исходный текст (SQL или C++), а на выходе получается машиночитаемый исполняемый файл (байт-код или машинный код).
3. Дополнительные материалы для чтения
Документ Атомарная фиксация описывает, как SQLite реализует транзакции.
Документ движок байт-кода содержит более подробную информацию о формате байт-кода, используемом SQLite, и о том, как просматривать и интерпретировать подготовленный оператор SQLite.
Документы планировщик запросов SQLite и планировщик запросов следующего поколения содержат подробную информацию об алгоритмах, используемых SQLite для реализации операторов SQL, и о том, как он выходит за рамки выбора подходящего алгоритма для каждого отдельного оператора SQL.
Последнее изменение этой страницы 2022-06-16 15:42:19 UTC
SQLite is in the Public Domain.
https://sqlite.org/howitworks.html