当我在不同的会话中运行并发 Amazon Redshift 操作时,我收到了"Serializable isolation violation on table"或"Relation does not exist"错误。
简短描述
Amazon Redshift 中的并发写入操作必须是可序列化的,这样事务才能按顺序运行。串行执行还必须产生与事务并行运行时相同的结果。有关详细信息,请参阅可序列化隔离。
解决方法
要解决可序列化隔离错误,请使用以下方法之一。
重试已取消的事务
如果 Amazon Redshift 检测到并发工作负载不可序列化,则表明应用程序逻辑中可能存在漏洞。重试导致错误的已取消事务。
使用中间提交
当发出提交或回滚指令时,事务即完成。如果事务在“从表中删除”操作运行之前提交,则系统会创建一个新事务并保留可序列化隔离。
以下示例使用中间 COMMIT 命令:
DELETE FROM XXXXX WHERE date = XXXXX';
→COMMIT;
BEGIN TRANSACTION;
DELETE FROM XXXXX WHERE date = XXXXX';
将非原子操作移出事务外
当两个事务中的单个操作相互交叉引用,这可能会影响另一个事务的结果时,请使用此方法。
如果其他操作的结果不需要具有原子性,请将 SELECT 语句移出其事务之外。
以下示例将 SELECT 语句移出其事务之外:
Session1_Redshift=# BEGIN;Session1_Redshift = # insert into tab1 values (1)Session1_Redshift = # END;
Session1_Redshift # select * from tab2;
Session2_Redshift # select * from tab1;Session2_Redshift =# BEGIN;
Session2_Redshift = # insert into tab2 values (1)
Session2_Redshift = # END;
前面的事务是可序列化的。如果您按顺序运行事务,则结果与您并行运行事务时的结果相同。
锁定每个会话中的所有表以强制序列化
LOCK 命令会阻止可能导致可序列化隔离错误的操作。运行 LOCK 命令时,请完成以下步骤:
- 锁定事务影响的所有表,包括事务内部只读 SELECT 语句影响的表。
- 无论执行操作的顺序如何,都以相同的顺序锁定表。
- 在执行操作之前,在事务开始时锁定所有表。
对并发事务使用快照隔离
可序列化隔离可实现严格的序列化。当 Amazon Redshift 无法将结果映射到同时运行的事务的序列顺序时,事务可能会失败。
快照隔离允许更高的并发性,因此可以成功完成对同一表中不同行的并发修改。
事务继续在数据库的最新提交版本或快照上运行。
您可以在数据库上设置快照隔离,并在 CREATE DATABASE 或 ALTER DATABASE 命令中包含 ISOLATION LEVEL 参数。
要查看数据库使用的并发模型,请运行以下 STV_DB_ISOLATION_LEVEL 查询:
SELECT * FROM stv_db_isolation_level;
The database can then be altered to SNAPSHOT ISOLATION:
ALTER DATABASE sampledb ISOLATION LEVEL SNAPSHOT;
更改数据库的隔离级别时,请遵循以下最佳实践:
- 要更改数据库隔离级别,必须具有超级用户或 CREATE DATABASE 权限。
- 您无法更改数据库环境的隔离级别。
- 您无法更改事务块内的隔离级别。
- 当其他用户连接到数据库时,更改隔离级别命令失败。
- 更改隔离级别命令可以更改当前会话的隔离级别设置。
有关详细信息,请参阅如何修复可序列化的隔离错误。
相关信息
ERROR:1023 DETAIL: Serializable isolation violation on a table in Redshift
ERROR:1018 DETAIL: Relation does not exist
管理并发写入操作