这是我的问题。假设我有一个长期运行的SELECT查询(#1):
select * from table1 -- assume this runs for a long time
它正在运行时,我从同一张表中运行另一个SELECT(#2)。它并行运行并在一秒钟内完成:
select top 1 * from table1
因此#2未被#1阻止。
现在,假设我要运行#3,即截断并重新加载table1:
begin tran
truncate table table1
insert into table1
select * from table2
commit
#3被#1阻止,必须等待,这是可以理解的。但是,它也会将TABLOCK放在table1上,并且#2都不能运行。基本上#2被#1阻止了。
问题:是否有一种方法可以不阻止其他查询的方式运行#3? 我希望看到#3等待#1,但是#2仍然可以运行。
我试图在运行#3之前检查锁,但是在sys.dm_tran_locks视图中看不到任何锁。我还能在其他地方看到它们吗?
答案 0 :(得分:0)
我已经有一段时间没有这样做了,但是您可以这样尝试:
begin tran
CREATE TABLE table1_new <(identical to table1, incl. indexes, keys and triggers)>
insert into table1_new
select * from table2
drop table table1
RENAME N'table1_new', N'table1', N'OBJECT'
commit
您可能需要尝试更高的隔离级别,以确保您的用户不会遇到任何“找不到对象”错误。
答案 1 :(得分:0)
好的,我找到了解决方案。不知道为什么以前对我不起作用,但是可以使用sys.dm_tran_locks视图。
基本上,我一直等到表上没有锁,然后开始截断/重新加载。
begin tran
--wait until there are no locks on the table
while exists(
select 1 from sys.dm_tran_locks
where resource_database_id = DB_ID()
and resource_associated_entity_id = OBJECT_ID(N'dbo.table1')
)
begin
waitfor delay '00:00:05'
end
truncate table table1
insert into table1
select * from table2
commit
答案 2 :(得分:0)
我的一位同事建议了另一个选项,我最终使用了该选项:在运行TRUNCATE之前设置LOCK_TIMEOUT。
如果它不能锁定表,它只会失败。 (当然,应该有一些机制可以稍后再运行)
SET LOCK_TIMEOUT 0
TRUNCATE TABLE table1
希望它可以帮助某人。