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

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

  1. Начало транзакции
  2. Создает таблицу staging_foo как foo
  3. Копирует данные из внешнего источника в staging_foo
  4. Выполняет массовую вставку / обновление / удаление на foo так, чтобы она соответствовала staging_foo
  5. Удалить staging_foo
  6. Commit transaction

Индивидуально этот процесс работает, но для того, чтобы обеспечить непрерывное потоковое обновление до foo и избыточности в случае сбоя, у меня есть несколько экземпляров процесса, выполняемого в одно и то же время. И когда это случается, я иногда получаю параллельные ошибки сериализации. Это связано с тем, что оба процесса воспроизводят одни и те же изменения в foo из foo_staging в перекрывающихся транзакциях.

Случается, что первый процесс создает таблицу staging_foo , а второй процесс блокируется при попытке создать таблицу с тем же именем (это то, что я хочу). Когда первый процесс совершает транзакцию (которая может занять несколько секунд), я обнаруживаю, что второй процесс разблокируется до завершения коммита. Таким образом, похоже, что получение моментальной копии таблицы foo перед фиксацией происходит, что приводит к сбою вставки / обновления / удаления (некоторые из которых могут быть избыточными).

Я теоретизирую на основе документации http://docs.aws.amazon.com/redshift/latest/dg/c_serial_isolation.html, где говорится:

Одновременные транзакции невидимы друг другу; они не могут обнаружить изменения друг друга. Каждая параллельная транзакция будет создавать моментальный снимок базы данных в начале транзакции. Снимки базы данных создаются в транзакции по первому вхождению большинства операторов SELECT, команд DML, таких как COPY, DELETE, INSERT, UPDATE и TRUNCATE, а также следующие команды DDL:

ALTER TABLE (для добавления или удаления столбцов)

СОЗДАТЬ ТАБЛИЦУ

ТАБЛИЦА ДРОБЛЕНИЯ

TRUNCATE TABLE

Приведенная выше документация несколько сбивает меня с толку, потому что сначала говорится, что моментальный снимок будет создан в начале транзакции, но впоследствии будет сказано, что моментальный снимок будет создан только при первом вхождении некоторых конкретных операций DML / DDL.

Я не хочу делать глубокую копию, где я заменяю foo вместо поэтапного обновления. У меня есть другие процессы, которые постоянно запрашивают эту таблицу, поэтому никогда не бывает времени, когда я могу ее заменить без перерыва. Другой вопрос задает аналогичный вопрос для глубокой копии, но для меня это не сработает: как я могу обеспечить синхронные операции DDL на заменяемой таблице?

Есть ли способ для выполнения моих операций таким образом, чтобы избежать параллельных ошибок сериализации? Мне нужно убедиться, что доступ для чтения доступен для foo поэтому я не могу LOCK эту таблицу.

OK, Postgres (и, следовательно, Redshift [более или менее]) использует MVCC (Multi Concurrency Control) для изоляции транзакций вместо модели блокировки db / table / row / page (как видно из SQL Server , MySQL и т. Д.). Упрощенно каждая транзакция работает с данными, как она существовала при запуске транзакции .

Таким образом, ваш комментарий «У меня есть несколько экземпляров процесса, запущенного в одно и то же время», объясняет проблему. Если процесс 2 запускается, пока выполняется процесс 1, процесс 2 не имеет видимости результатов процесса 1.