【问题标题】:Lock a table during multiple statements in a stored procedure在存储过程中的多个语句期间锁定表
【发布时间】:2017-12-25 00:16:34
【问题描述】:

我希望通过 Teradata 事务实现等效的快照隔离。 Oracle 支持这种类型的隔离,但 Teradata 不支持(至少在我知道的版本 14 或更早版本中不支持)。目标是创建一个删除表格内容然后重新填充所有内容的过程,同时防止其他用户读取/写入表格。

我遇到了begin request 语句,据我了解,它允许优化器了解请求中的所有各种表锁。

我编写了下面的过程,但不知道如何可靠地调试它,就像我在 .NET 应用程序中测试线程锁定一样简单(易于设置断点和监视其他线程)。在 Teradata 中,不确定我在这里写的内容是否会在整个过程中正确锁定 mydb.destinationtable。这是正确的吗?

编辑:我会补充说该程序确实有效。它只是能够在执行 DELETE/INSERT 时正确地为 SELECT 计时。

replace procedure mydb.myproc()
begin
    begin request

    locking mydb.destinationtable for exclusive
    delete mydb.destinationtable;

    locking mydb.destinationtable for exclusive
    insert into mydb.destinationtable
    select * from mydb.sourcetable;

    end request;
end;

【问题讨论】:

  • 1.使用视图而不是表来读取数据。 2. 加载时删除视图。 3. 加载完成后重新创建视图。据我所知,您还可以使用 mload,它会为您处理所有锁定。
  • 为什么不使用 TASM 拒绝(或延迟)针对在 ETL 期间加载的表(或数据库)的请求?不是理想的解决方案,但解决了锁隔离问题。或者,您是否可以在最终用户访问表的视图中使用队列表和使用嵌套 SELECT 语句定义的列,该表试图访问队列表中的令牌。如果令牌丢失,查询进入 QT_DELAYED 状态。
  • @RobPaller 在研究 TASM 和查看队列表示例时,似乎涉及很多设置和/或样板。并不是说他们不会工作,而是只是在寻找一种方法,在存储过程中(即,不是 BTEQ 等),1)在表上设置排他锁,2)执行多个语句(甚至不一定反对锁定表),然后 3)释放锁。 dnoeth 的回答 似乎 确认我的 OP 代码会做到这一点,尽管我还不太了解瞬态日志的潜在性能影响。
  • 只是关于如何调试行为的建议。创建一个假表,并在您的过程中插入此假表的更新,您通常会在其中设置断点。在启动该过程之前,从另一个会话中锁定假表。这样,您的过程将在您需要的地方阻塞,您可以测试锁定目标表对其他用户的影响。
  • @Insac 我非常喜欢这个想法。我将如何无限期锁定一张桌子?

标签: teradata


【解决方案1】:

BEGIN REQUEST/END REQUEST 创建一个所谓的多语句请求 (MSR),这与使用 F9 在 SQL 助手中提交两个请求相同。

要查看计划,请按 F9 运行:

EXPLAIN
locking mydb.destinationtable for exclusive
delete mydb.destinationtable;

insert into mydb.destinationtable
select * from mydb.sourcetable;

或在 BTEQ 中:

EXPLAIN
locking mydb.destinationtable for exclusive
delete mydb.destinationtable
;insert into mydb.destinationtable
select * from mydb.sourcetable;

顺便说一句,第二把锁是多余的。

但是。当您将 Delete & InsSel 作为单个事务运行时,两者都将是 Transient Journalled。这比单独的请求慢得多

执行此操作的更常见方法是使用目标表的两个副本并基于视图而不是表进行访问:

-- no BEGIN/END REQUEST
insert into mydb.destinationtable_2
select * from mydb.sourcetable;

-- there's just a short dictionary lock
-- all requests against the view submitted before the replace use the old data
-- and all submitted after the new data
replace view myview as 
select * from mydb.destinationtable_2;

delete from mydb.destinationtable_1;

现在您的 SP 只需要在 1 和 2 之间切换的逻辑(基于 table [not] empty

【讨论】:

  • 我真的很想避免交换表/视图。有没有办法在存储过程的整个过程中对表设置排他锁?至于冗余锁,您是说仅在DELETE期间放置锁也会将锁应用于INSERT?至于被临时记录,有没有办法在同一个事务下作为单独的语句运行,同时还能够在事务提交之前独占锁定我的表?
  • 至于为什么我不想交换源是因为我想模拟Oracle的快照隔离。也许甲骨文在幕后也在做同样的事情,但它是隐含的。我不想在 Teradata 中手动模拟这种类型的隔离。
  • 当您执行 MSR 时,您将 DEL 和 INS/SEL 在单个请求中发送到优化器,因此优化器知道两个语句都访问同一个表并应用最严格的锁。为什么你认为你需要快照隔离,不就是一个仓库吗?您正在处理什么样的数据,您将多久运行一次该程序?
  • 我继续使用“快照隔离”一词可能是在做坏事。在 Oracle 中,您可以在一个事务中运行多个查询。在提交更改之前,任何查询数据的人都会看到它在事务打开之前就已经存在,并且只有在提交时才能看到更改。在我的例子中,如果有人在 DELETE 之后但在 INSERT 之前查询数据,他们的查询将返回 0 个结果。我想通过专门锁定目标表来降低这种风险,这样所有针对它的查询都必须等到锁被释放。
  • 它还负责所有必须交换视图的样板,根据计数管理要使用的视图,确保在需要添加新列时所有负载表 DDL 同步,等等。基本上,我想独占锁定一个表,运行尽可能多的 SQL 语句(甚至不必在事务中),然后在完成后解除锁定。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多