Что делает данная разработка?
Реализована возможность управления использованием методов Begin/EndReadSequence() при выполнении запроса. Если запрос выполняется внутри транзакции, то эти методы исполняются с блокировкой таблиц. Если запрос выполняется вне транзакции, то эти методы не исполняются, даже если они вызываются в 1SQLite. Т.е. если запрос выполняется внутри модуля проведения документа, то эти методы будут исполняться, и запрос будет выполняться быстро. В остальных случаях пользователь может управлять режимом выполнения запроса с помощью функций Начать/Зафиксировать/ОтменитьТранзакцию().
Причины возникновения ошибки.
Для ускорения выполнения запросов в 1SQLitе используется метод BeginReadSequence() штатного движка 1С. Данный метод значительно ускоряет последовательный просмотр таблицы по индексу. Но для этого в штатном движке выполняется блокировка таблицы по записи. Если в другой сессии делается попытка обновления данной таблицы внутри метода EndTransaction(Commit), то проверка освобождения таблицы выполняется в цикле N раз (примерно за одну минуту), после чего выдаётся (!) команда обновления таблицы. И СУБД возвращает этому методу код возврата “-56”. В штатном движке данный код возврата обрабатывается как требование аварийного завершения сессии 1С. Т.к. это происходит в момент записи данных транзакции, то в базе данных может образоваться противоречивая информация.
Пути решения.
1) Использовать разработки, снимающие 100% занятость процессора при ожидании освобождения блокировки. В этих разработках в цикл опроса добавляется функция sleep(). Т.е. суммарное время опроса освобождения таблицы увеличивается и за это время запрос из другой сессии 1С может успеть завершиться. Но может и не успеть. :-(((
2) Использовать разработку “DBEng32 SEQ”. В этой разработке перехватываются методы BeginReadSequence() и EndReadSequence(). И в них добавляются вызовы методов BeginTransaction(), PutTLock(Full) перед выдачей BeginReadSequence(). А после вызова метода EndReadSequence() вызывается EndTransaction(Commit). Таким образом, запрос выполняется в транзакции с попыткой блокировки таблицы, для которой выдан метод BeginReadSequence(). Ожидание освобождения таблицы осуществляется другими алгоритмами, на которые влияет, установленное в настройках 1С “Время ожидания захвата таблицы Базы Данных (сек.)”. И в случае неуспешного ожидания освобождения таблицы сессия 1С не завершается аварийно, а происходит откат транзакции. Очевидным недостатком такого решения является тот факт, что общая производительность системы падает из-за неоправданных ожиданий завершения запроса, не выполняющего обновления данных. Кроме того, могут возникать клинчи. Но порчи базы данных не происходит. Естественно, что такой алгоритм можно перенести из “DBEng32 SEQ” в 1SQLite.
3) Разработать алгоритм “внешней блокировки” таблиц. Общий смысл алгоритма в том, что перед выполнением запроса делается попытка блокировать внешние ресурсы, сопоставленные реальным таблицам базы данных используемым в запросе. Таблицы (внешние ресурсы) блокируются до начала выполнения всего запроса. После выполнения запроса блокировки снимаются. А перед выполнением метода EndTransaction(Commit) осуществляется проверка и ожидание освобождения этих внешних ресурсов. Такой алгоритм позволит избежать клинчей и неоправданного ожидания окончания выполнения запросов в других сессиях. Данный алгоритм можно реализовать с участием “DBEng32 SEQ” или в самой 1SQLite осуществить перехват метода EndTransaction().
4) Отказаться от использования метода BeginReadSequence() в 1SQLite. Но в этом случае скорость выполнения запроса будет сопоставима со скорость выполнения алгоритма выборки данных штатными языковыми средствами 1С.
5) Использовать другие СУБД, свободные от данной проблемы, вместо штатного движка 1С. Например, DBEng32 для Advantage или CodeBase. Но для этого надо обеспечить совместимость 1SQLite c этими разработками.