RussianLDP Рейтинг@Mail.ru
WebMoney: 
WMZ Z294115950220 
WMR R409981405661 
WME E134003968233 
Visa 
4274 3200 2453 6495 

Small. Fast. Reliable.
Choose any three.
Как SQLite работает

1. Фон

SQLite это программная библиотека, которая переводит дисковые запросы I/O высокого уровня, произведенные приложением в операции I/O низкого уровня, которые могут быть выполнены операционной системой. Приложение строит запросы I/O высокого уровня, используя язык SQL. SQLite переводит каждый SQL-оператор высокого уровня в последовательность из многих запросов I/O низкого уровня (откройте файл, прочитайте несколько байтов из файла, напишите несколько байтов в файл и т.д.), которые делают работу, которую требует SQL.

Прикладная программа могла сделать весь свой диск I/O прямыми обращениями к операционной системе или при помощи движка хранения ключа/значения как в Berkeley DB или RocksDB. Но есть преимущества для использования высокоуровневого интерфейса на основе языка SQL.

  1. SQL очень высокоуровневый язык. Несколько строк на SQL могут заменить сотни или тысячи строк процедурного кода. SQL таким образом уменьшает объем работы и таким образом помогает сократить количество ошибок в приложении.

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

  3. SQLite часто быстрее, чем прямой I/O низкого уровня. Это парадоксально. Можно было бы ожидать, что интерфейс высокого уровня, такой как SQLite наложит издержки во время выполнения. И, теоретически, это правильно. Но на практике, основанные на SQL системы, такие как SQLite, делают столько закулисной оптимизации, на которую у разработчика приложений никогда не было бы времени, что основанные на SQL системы обеспечивают чистое увеличение производительности.

1.1. SQLite отличается от большинства других баз данных SQL

Есть много основанных на SQL доступных систем управления базами данных помимо SQLite. Общие варианты включают MySQL, PostgreSQL и SQL Server. Все эти системы используют язык SQL, чтобы общаться с приложением, точно так же, как SQLite. Но это другие системы, отличающиеся от SQLite в важных отношениях.

  1. SQLite безсерверная библиотека программного обеспечения, тогда как другие системы это клиент-сервер. С MySQL, PostgreSQL, SQL Server и другими приложение посылает сообщение, содержащее некоторый SQL к отдельному потоку сервера или процессу. Этот отдельный поток или процесс выполняют требуемый I/O, затем передают результаты обратно в придлжение. Но нет никакого отдельного потока или процесса с SQLite. SQLite работает в том же самом адресном пространстве, где приложение, используя тот же самый счетчик команд и хранение кучи. SQLite не делает никакого межпроцессного взаимодействия (IPC). Когда приложение посылает SQL-оператор в SQLite (вызывом соответствующей библиотечной подпрограммы SQLite), SQLite интерпретирует SQL в той же самом потоке. Когда установленный порядок API SQLite возвращает управление, он не оставляет позади фоновых задач, которые работают отдельно от приложения.

  2. База данных SQLite это единственный обычный файл на диске (с четко определенным форматом файла). С другими системами "база данных" обычно представляет собой большое количество отдельных файлов, скрытых в неясных каталогах файловой системы, или даже распространенных на многие машины. Но с SQLite, полная база данных это просто обычный дисковый файл.

2. SQL язык программирования

Лучший способ понять, как работает база данных SQL, это думать о SQL как о языке программирования, а не как о "языке запросов". Каждый SQL-оператор по сути отдельная программа. Приложения строят исходные файлы программы SQL и посылают их в ядро базы данных. Ядро базы данных собирает исходный код SQL в выполнимую форму, выполняет, затем передает результат обратно.

В то время как SQL язык программирования, это отличается от других языков программирования, таких как C, Javascript, Python или Go. SQL это декларативный язык, а другие императивные. Это важное различие, которое имеет последствия для дизайна компилятора, используемого, чтобы перевести исходный текст программы в формат исполняемых файлов. Однако, те детали не должны умалять то, что SQL действительно просто другой язык программирования.

2.1. Шаги обработки языка программирования

Все языки программирования обрабатываются в два шага:

  1. Переведите исходный текст программы в формат исполняемых файлов.

  2. Управляйте исполняемым файлом, произведенным на предыдущем шаге, чтобы выполнить желаемое действие.

Все языки программирования используют эти два основных шага. Основное различие находится в формате исполняемых файлов.

quot;Компилируемые" языки, такие как C++ и Rust, переводят исходный текст в машинный код, который может быть непосредственно выполнен используемым оборудованием. Существуют системы базы данных SQL, которые делают то же самое с SQL: они переводят каждый SQL-оператор непосредственно в машинный код. Но тот подход необычен и не является подходом, проявленным SQLite.

Другие языки как Java, Perl, Python и TCL, как правило, переводят исходный текст программы в байт-код. Этим управляют через транслятор, который читает байт-код и проводит желаемые операции. SQLite использует этот подход. Если вы будете предшествовать какому-либо SQL-оператору с ключевым словом "EXPLAIN" в SQLite, это покажет вам байт-код, который произведен.

Другой подход должен перевести исходный текст программы в дерево объектов в памяти. Это дерево "исполняемый файл". Интерпретатор выполняет исполняемый файл, идя по дереву. Это техника, используемая MySQL, PostgreSQL и SQL Server.

Конечно, не каждый язык соответствует аккуратно одной из вышеупомянутых категорий. Это относится движкам базы данных SQL и к более знакомым императивным языкам программирования. JavaScript известен использованием гибридной модели выполнения, где код первоначально собран в дерево объектов, но может далее транслироваться (с использованием компиляции) вниз до более эффективного байт-кода или вовсе в машинный код как средство повышения производительности.

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

2.2. Компилирование программы SQLite

Когда программа SQL представлена SQLite, первый шаг должен разделить исходный текст на токены. Токен мог бы быть:

  • Ключевые слова языка, например, "SELECT" или "UPDATE".
  • Идентификатор для таблицы, колонки или переменной.
  • Символы пунктуации наподобие ",", "==" или ";".
  • Литеральные значения: числовые или строковые константы.
  • Комментарии или пробелы.

Комментарии или пробелы пропущены. Все другие символы поданы в LALR(1) Parser, который анализирует структуру входной программы и производит Abstract Syntax Tree (AST) для входной программы.

AST передает данные генератору кода. Генератор кода решает символьные имена в AST, соответствуя названиям колонок и таблиц во входе SQL в фактические колонки и таблицы базы данных. Генератор кода также делает различные преобразования AST, чтобы "оптимизировать" его. Наконец генератор кода выбирает соответствующие алгоритмы, чтобы осуществить операции, которые требует AST, и строит байт-код, чтобы провести те операции.

Байт-код, произведенный генератором кода, называют "подготовленным запросом". Перевод исходного текста SQL в подготовленный запрос походит на преобразование программы C++ в машинный код, вызывая gcc или clang. Человекочитаемый исходный текст (SQL или C++) входит, а выходит машиночитаемый исполняемый файл (байт-код или машинный код).

3. Дополнительные материалы для чтения

  • Атомные передачи описывает, как SQLite осуществляет транзакции.

  • Движок байт-кода дает больше информации о формате байт-кода, используемом SQLite, как рассмотреть и интерпретировать подготовленный запрос SQLite.

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