SQLite неисключительная зарезервированная блокировка?
Я пытался улучшить производительность SQLite для своего сайта, особенно в отношении транзакций. По сути, я ищу способ отложить запись в базу данных в процессе, чтобы все они могли быть выполнены одновременно. Однако, пока я накапливаю запросы на обновление, мне бы хотелось, чтобы другие процессы могли выполнять чтение и запись в базу данных и блокировать файл для записи только после того, как в процессе будет выполнен коммит.
При просмотре документации кажется, что, как только в транзакции введена команда обновления, процесс получает зарезервированную блокировку, что (если я правильно помню) означает, что любой другой процесс, который пытается добавить запрос на обновление в свою собственную транзакцию или зафиксировать транзакцию не удается, и поэтому блокируется, пока транзакция не фиксируется в процессе с блокировкой.
Я уверен, что есть очень хорошие причины целостности данных против этой конкретной функции. Все, что я могу сказать, это то, что в моем случае нет опасности одновременно выполнять эти обновления.
Одним из решений является то, что в каждом процессе я мог бы накапливать текст запросов, которые я хочу вызвать, в массиве, а затем зацикливать его, как только я буду готов к записи, но мне интересно, возможно ли сделать транзакцию SQLite для сделай это для меня автоматически.
Обновление: Я имею в виду, когда говорю "делать все свои обновления сразу", по сути, используя транзакции в SQLite, чтобы получить только ИСКЛЮЧИТЕЛЬНУЮ блокировку и запись на диск один раз для каждого процесса, а не один раз для запроса. Это приводит к 100-кратному ускорению с использованием SQLite.
Я провел некоторое базовое тестирование, и кажется, что если у вас есть несколько процессов, добавляющих запросы к своим транзакциям, когда вы нажимаете запрос на обновление, процесс пытается получить зарезервированную блокировку. Поскольку только один процесс может иметь зарезервированную блокировку, это означает, что любые другие процессы, пытающиеся получить блокировку, будут блокироваться, пока процесс с блокировкой не завершит транзакцию.
Я признаю, что эта проблема может быть преждевременной оптимизацией, так как мне еще не приходилось сталкиваться с какими-либо штрафами за производительность, но я провел несколько простых тестов, и 100 пользователей, каждый из которых для создания и запуска транзакции со 100 запросами, занимает около 4 секунд в PHP на моей машине.
2 ответа
SQLite поддерживает ATTACH для подключения одной базы данных к другой. Возможно, вы можете накапливать свои данные в отдельной базе данных, и когда вы будете готовы объединить накопленные строки, присоедините отдельную базу данных, скопируйте строки в одном выражении и отсоедините.
Редактировать: аналогичное предложение было сделано в ветке списка рассылки на sqlite-users с последующим обсуждением.
Лучше, чем прикрепить базу данных, просто создать временную таблицу. (СОЗДАТЬ ВРЕМЕННОЕ...)
И взгляните на новый режим журнала WAL, который точно выполняет то, что вы пытаетесь сделать вручную, и позволяет одновременную запись и чтение (но не одновременную запись).
#pragma journal_mode = WAL