Database vertica db中的死锁,用于并发访问同一表的不同行

Database vertica db中的死锁,用于并发访问同一表的不同行,database,deadlock,vertica,Database,Deadlock,Vertica,我在Vertica数据库中有一个表,如下所示: SET SESSION AUTOCOMMIT TO OFF; UPDATE log_table SET start_time = CURRENT_TIMESTAMP WHERE process_name = 'p1'; SELECT last_val FROM log_table WHERE process_name ='p1'; UPDATE log_table SET end_time = CURRENT_TIMESTAMP WHERE p

我在Vertica数据库中有一个表,如下所示:

SET SESSION AUTOCOMMIT TO OFF;
UPDATE log_table SET start_time = CURRENT_TIMESTAMP WHERE process_name = 'p1';
SELECT last_val FROM log_table WHERE process_name ='p1';
UPDATE log_table SET end_time   = CURRENT_TIMESTAMP WHERE process_name = 'p1';
COMMIT;

有四个进程p1、p2、p3、p4同时运行,并对各自的行执行操作,即

p1--->在p1行上选择最后一个值、更新开始时间、更新结束时间

p2--->在p2行上选择最后一个值、更新开始时间和更新结束时间

p3--->在p3行上选择最后一个值、更新开始时间、更新结束时间

p4--->在p4行上选择最后一个值、更新开始时间、更新结束时间

所有四个进程仅访问其自身的特定行,例如p1从不访问p2的行

然而,当p1在p1的行上运行select查询并持有锁时,我面临死锁问题,同时p4尝试更新p4的行

事务隔离级别已读取并提交

我能做些什么来避免这种僵局

编辑1: 以下是流程执行的示例查询:

UPDATE $log_table SET start_time = CURRENT_TIMESTAMP(1) WHERE process_name = '$taskname'

SELECT last_value FROM $log_table WHERE process_name ='$taskname'

UPDATE $log_table SET end_time = CURRENT_TIMESTAMP(1) WHERE process_name = '$taskname'
编辑2: 示例perl脚本

$taskname = "p1"   # respective process names. for process1 its p1. for process2 its p2 and so on. #
$log_table = "config table name"

# Update start time 
$current_timestamp = localtime();
$sqlstmt = "UPDATE $log_table SET start_time = '$current_timestamp' WHERE process_name = '$taskname'";
$db->prepare("$sqlstmt") or handle_error();
$handle->execute() or handle_error();

# do other stuff 

# Fetch last modified value
$sqlstmt = "SELECT last_value FROM $log_table WHERE process_name ='$taskname'";
$db->prepare("$sqlstmt") or handle_error();
$handle->execute() or handle_error();
$result = $handle->fetchrow();
# do other stuff


# Update end time
$current_timestamp = localtime();
$sqlstmt = "UPDATE $log_table SET end_time = '$current_timestamp' WHERE process_name = '$taskname'";
$db->prepare("$sqlstmt") or handle_error();
$handle->execute() or handle_error();
$result = $handle->fetchrow();

您面临的问题是,Vertica实际上并不更新现有行,但它通过在物理存储中添加新的删除向量,将现有行标记为已删除,并插入新行。这还涉及表上的独占锁。您的连接是否自动提交?如果没有,请尝试更改为自动提交,看看会发生什么。如果这没有帮助,还有一些设计的可能性

我创建了表和四个脚本,如下所示:

SET SESSION AUTOCOMMIT TO OFF;
UPDATE log_table SET start_time = CURRENT_TIMESTAMP WHERE process_name = 'p1';
SELECT last_val FROM log_table WHERE process_name ='p1';
UPDATE log_table SET end_time   = CURRENT_TIMESTAMP WHERE process_name = 'p1';
COMMIT;
然后,我使用一个查询驱动程序并行运行这四个脚本。在执行脚本中的每个语句之间等待两秒钟。我还交替添加或删除
开始工作
/
提交工作
语句。恐怕我不能触发僵局,所以我在这里瞎飞

一种侵入性较小的替代方案:每个进程名称使用不同的ROS容器:

通过进程名称重新组织更改表日志\u表分区

您可以幸运地减少死锁—虽然删除(更新是删除,然后是插入)总是发出独占表锁—但它们之间的死锁可能会少一些

暴力的方式是:

CREATE TABLE log_p1 (last_val INT start_time TIMESTAMP,end_time TIMESTAMP);
CREATE TABLE log_p2 (last_val INT start_time TIMESTAMP,end_time TIMESTAMP);
CREATE TABLE log_p3 (last_val INT start_time TIMESTAMP,end_time TIMESTAMP);
CREATE TABLE log_p4 (last_val INT start_time TIMESTAMP,end_time TIMESTAMP);
CREATE VIEW log_table AS -- just for reporting, not for maintenance
          SELECT 'p1' AS proc_name, * FROM log_p1
UNION ALL SELECT 'p2' AS proc_name, * FROM log_p2
UNION ALL SELECT 'p3' AS proc_name, * FROM log_p3
UNION ALL SELECT 'p4' AS proc_name, * FROM log_p4
;
这四个脚本只在
p4
p1
方面有所不同:

SELECT * FROM p1; -- fetch single row output into your application
TRUNCATE TABLE p1;
-- bind "last_val" and "end_time" host variables
INSERT INTO p1 VALUES(? , CURRENT_TIMESTAMP, ?);
SELECT last_val FROM log_p1;
TRUNCATE TABLE p1;
-- bind "last_val" and "start_time" host variables
INSERT INTO p1 VALUES(? , ?, CURRENT_TIMESTAMP);
COMMIT;

六羟甲基三聚氰胺六甲醚。。。你能分享你交易的SQL吗?顺便提一下P1应该在提交事务时释放其锁,以便P4可以继续…查询不会像您编写的那样运行<代码>当前时间戳可以工作,但
当前时间戳(1)
不能。您希望从
中选择$log\u表中的最后一个值,其中process\u name='$task\u name'
,得到多少行?你能提供或补充样本数据来说明吗?@marcothesane对不起,我的不好。我给出了一些查询示例。1.请检查我的最新编辑,我添加了一个perl脚本。实际上,我是从perl脚本触发查询的。相同perl脚本的四个副本是p1、p2、p3和p4。我不是从查询中获取当前的\u时间戳,而是从perl脚本中获取,所以这里不关心当前的\u时间戳。2.只有四排。正如我在问题中给出的,同样的数据也会存在。谢谢你,到目前为止。如何处理
$result
变量?我的意思是:
从$log\u表中选择最后一个值,其中process\u name='$taskname'
将返回一个游标,其单列行数与
$log\u表中的行数相同。但是您只运行一个
fetchrow()
,而没有控制,它将是您得到的第一个
最后一个值。我正在创建一个表:
process\u name CHAR(2)、start\u time INT、end\u time INT、last\u value INT
,并尝试自己触发死锁。你正在使用的桌子不同吗?@marcothesane是的,没错。应该是这样的。我只需要最后一列的第一个。select查询只返回一个值,因为每个进程只有一行。之后我对$result值进行了一些计算,但这在这里并不重要。我使用的表与我在问题中给出的表相同,也与您的表模式相同。