Почему процедура выполняется параллельно, даже если она заблокирована?

У меня есть процедура `exec_batch_from_id`, которая выполняет определенный шаг ETL, а затем запускает несколько своих инстансов параллельно, инициируя выполнение следующих шагов. Однако возникла проблема: в одном случае процедура запускается дважды одновременно другой процедурой, и каждый инстанс завершает свою работу, вызывая 23-й шаг, что недопустимо. 

В начале процедуры прописано: 
```sql
LOCK TABLE df.batch_log IN ACCESS EXCLUSIVE MODE;
```
При этом не используются другие таблицы, и вся работа связана именно с этой таблицей. Я предполагаю, что это блокировка должна предотвратить параллельное выполнение процедуры. Это критически важно, поскольку каждая параллельная сессия должна учитывать изменения, внесенные предыдущими инстансами, иначе следующий шаг ETL может быть вызван дважды.

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

У меня нет опыта в вопросах конкурентности, возможно, я неверно проанализировал ситуацию. Однако мне нужно организовать очередь, чтобы каждый следующий инстанс видел изменения, сделанные предыдущим. 

Дополнительно, я провел отладку с помощью таблицы и заметил, что работа инстансов пересекается.
  • 18 марта 2025 г. 15:04
Ответы на вопрос 1
Проблема, с которой вы столкнулись, действительно может быть связана с конкуренцией между параллельными сессиями, и ее решение требует понимания механизма блокировок и уровней изоляции транзакций в вашей системе управления базами данных (СУБД).

1. **Блокировка таблицы**: Вы используете `LOCK TABLE df.batch_log IN ACCESS EXCLUSIVE MODE;`, что действительно должно предотвратить доступ к таблице `df.batch_log` с других сессий, пока текущая сессия не завершит работу. Однако, стоит проверить, действительно ли блокировка применяется в нужной части кода и не происходит ли коммит транзакции до того, как блокировка активна.

2. **Уровень изоляции транзакций**: Возможно, следует обратить внимание на уровень изоляции транзакций. Например, уровень изоляции `READ COMMITTED` позволяет сессиям видеть изменения, сделанные другими транзакциями. В этом случае может быть полезно изменить уровень изоляции для вашей процедуры на более строгий, например, `SERIALIZABLE`, чтобы обеспечить лучшую изоляцию.

3. **Использование механизма очередей**: Если параллельное выполнение инстансов действительно недопустимо, можно рассмотреть вариант использования очереди или системы управления задачами, чтобы последовательно выполнять инстансы. Это может быть реализовано через создание отдельной таблицы или использование брокеров сообщений.

4. **Проверка на существование активных инстансов**: Перед запуском нового инстанса проверьте, нет ли уже активных работ. Это можно сделать, например, с помощью запроса к таблице, где фиксируются статусы всех запущенных инстансов.

5. **Обработка исключений**: Обработка исключений, как правило, не мешает блокировкам. Однако стоит убедиться, что в случае возникновения ошибки блоку не "выскочат" по времени, что может привести к освобождению блокировок до завершения текущей транзакции.

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

В зависимости от конкретной реализации и используемой СУБД, возможно, потребуются более комплексные механизмы управления процессами. Сложные сценарии ETL, где порядок исполнения шагов критичен, могут потребовать детального проекта на уровне архитектуры приложения, чтобы гарантировать, что параллелизм не приведет к ошибкам или нежелательным последствиям.
Похожие вопросы