我们正在尝试更新/删除数十亿行表中的大量记录。由于这是一张受欢迎的桌子,因此这张桌子的不同部分有很多活动。任何大型更新/删除活动都被长时间阻塞(因为它正在等待获得所有行的锁或页锁或表锁),从而导致超时或需要多天才能完成任务。
因此,我们正在更改一次删除小批量行的方法。但是我们想检查选定的(比如 100、1000 或 2000 行)当前是否被不同的进程锁定。
这是可行的吗?
谢谢,ToC
我试图在 SQL Server 中找到一些关于阻塞的信息,但我找不到关于它是什么以及它是如何发生的简明解释。你能帮我解惑吗?
我正在尝试了解/学习如何追踪被阻止会话的详细信息。
所以我创建了以下设置:
create table foo (id integer not null primary key, some_data varchar(20));
insert into foo values (1, 'foo');
commit;
Run Code Online (Sandbox Code Playgroud)
现在我从两个不同的客户端连接到数据库两次。
第一届会议议题:
begin transaction
update foo set some_data = 'update'
where id = 1;
Run Code Online (Sandbox Code Playgroud)
我明确没有在那里提交以保持锁定。
在第二个会话中,我发布了相同的声明,当然,由于锁定而等待。现在我正在尝试使用不同的查询来查看会话 2 正在等待foo表。
sp_who2 显示以下内容(我删除了一些列以仅显示重要信息):
SPID | 状态 | BlkBy | 数据库名称 | 命令 | SPID | 请求ID -----+--------------+-------+---------+---------- ------+------+------- 52 | 睡觉| . | 食物b | 等待命令 | 52 | 0 53 | 睡觉| . | 食物b | 等待命令 | …
在另一个应用程序中,我被糟糕的设计震惊了:多个线程EnsureDatabaseSchemaExists()同时执行一个方法,它看起来基本上是这样的:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'MyTable') AND type = N'U') BEGIN
CREATE TABLE MyTable ( ... );
END
Run Code Online (Sandbox Code Playgroud)
但是,即使在 SERIALIZABLE 事务中执行,此代码似乎也不是线程安全的(即并行代码尝试多次创建表)。是否有机会强制 SELECT 语句获取阻止另一个线程执行相同 SELECT 语句的锁?
是否有更好的多线程 EnsureSchemaExists() 方法模式?
I was attempting to answer the following stackoverflow question:
After posting a somewhat naive answer, I figured I'd put my money where my mouth was and actually test the scenario I was suggesting, to be sure I wasn't sending the OP off on a wild goose chase. Well, it's turned out to be much harder than I thought (no surprise there …
假设我有以下长时间运行的查询
UPDATE [Table1]
SET [Col1] = 'some value'
WHERE [Col2] -- some clause which selects thousands of rows
Run Code Online (Sandbox Code Playgroud)
并假设在上述查询运行时执行以下查询
SELECT *
FROM [Table1]
Run Code Online (Sandbox Code Playgroud)
第一个查询是否阻止第二个查询运行,直到第一个查询完成?如果是这样,第一个查询会阻止第二个查询在所有行上运行还是仅在 WHERE 子句中涉及的行上运行?
编辑:
假设第二个查询是
SELECT [Col1], [Col2]
FROM [Table1]
WHERE [Col2] -- some clause whose matching elements overlap those from
-- the clause in the first query and which has additional matching elements
Run Code Online (Sandbox Code Playgroud) 这是一个谦虚的问题,本着增加我的知识的精神提出的;请温柔地回应。
作为一名长期的应用程序开发人员,我在某种程度上知道事务是什么(我一直在使用它们)。暂且不谈事务隔离级别,在较高级别上,事务允许完全完成或根本不完成工作块,并允许与其他数据库修改活动进行一定程度的隔离。
我还知道(在各种数据库中)锁是什么,或者至少知道一个锁的行为(如果我以某种方式明确地锁定一个表,那么没有其他进程或线程可以更新有关该表的任何内容)。
我现在最明显的不明确的是:在各种数据库中,当我明确地锁定一行或一台,我在用人所使用的数据库的交易设施在幕后进行交易正常工作完全一样的结构?
也就是说,我突然想到,为了使事务具有原子性和隔离性,它必须进行一些锁定。这个事务启动的、事务隐藏的锁定是否与各种数据库让我通过诸如SELECT FOR UPDATE或显式LOCK命令之类的结构访问的锁定类型相同?还是这两个概念完全不同?
再次,我为这个问题的幼稚道歉;我很高兴被指出更基础的来源。
在超时之前,我将在哪里设置查询在 MySQL 5.0.68 中等待锁定的最长时间?
如果我通过高延迟网络对 SQL Server 数据库进行一次调用,是否会由于该延迟而发生表锁定?假设我查询表 A 中的某些记录,并且 SQL Server 必须通过慢速网络返回该数据 - 当服务器通过网络发送响应时,表 A 上是否存在读取锁定,或者 SQL Server 在发送之前是否释放锁定响应?
此外,答案是否会根据响应的大小而有所不同?如果它只需要返回几 KB 与几百 MB,那会有什么不同吗?
创建显式事务、运行查询和关闭事务显然会导致表锁定,因为事务的持续时间与我的延迟相关。
我有 2 个查询,当同时运行时会导致死锁。
查询 1 - 更新包含在索引 (index1) 中的列:
update table1 set column1 = value1 where id = @Id
Run Code Online (Sandbox Code Playgroud)
在 table1 上使用 X-Lock,然后在 index1 上尝试 X-Lock。
查询 2:
select columnx, columny, etc from table1 where {some condition}
Run Code Online (Sandbox Code Playgroud)
在 index1 上使用 S-Lock,然后在 table1 上尝试 S-Lock。
有没有办法在保持相同查询的同时防止死锁?例如,我可以在更新之前以某种方式在更新事务中的索引上使用 X-Lock 以确保表和索引访问的顺序相同 - 这应该防止死锁?
隔离级别为 Read Committed。为索引启用了行锁和页锁。同一个记录可能同时参与了两个查询 - 我无法从死锁图中判断出来,因为它没有显示参数。
locking ×10
sql-server ×7
blocking ×1
deadlock ×1
mysql ×1
mysql-5 ×1
network ×1
queue ×1
transaction ×1