2

我有一个名为Products多列的表。它是用于报告目的的临时表。多个用户请求将同时处理数据到该表。有单独的存储过程可以对该表进行 DML 操作。

表结构:

CREATE TABLE Products (
  instance uniqueidentifier,
  inserted datetime,
  col1, 
  col2,
  ...
)

inserted列将被填充GETDATE()以包含插入每行的时间,并且该instance列将包含来自 的值newid()。一个用户请求将有一个唯一的 id,但可能有数百万行。以下是将并发执行的查询,这会导致死锁。请给我提意见

查询一:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
DELETE P 
FROM Products (NOLOCK) 
WHERE instance = 'XXXX-xxx-xxx-xx'

查询 2:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
DELETE P 
FROM Products (NOLOCK) 
WHERE inserted <= DATEADD(hh, -10, GETDATE())

注意:非聚集索引是在实例列上创建的。

请告诉我在这种情况下我可以使用哪种锁。

注意我不能主键,因为当我向表中插入 1000 万行时它会消耗时间(这对于一个事务;有 20 个并发事务)。报告应尽快生成。我的程序有多个 35 个 DML 语句,大约有 15 个 DELETE 语句,例如带有其他列的列(DELETE FROM table WHERE instance = @instance AND col1 = @col1)。

4

2 回答 2

6

(1)你应该停止使用read uncommitted隔离。至少使用read committed.

(2) 有很多事情可以尝试避免死锁,例如确保您的不同事务以相同的顺序访问数据库对象等。这值得一读 - http://support.microsoft.com/kb/ 169960

(3) 为您的表禁用锁升级(更精细的锁因此更好的并发性,但更多的锁开销):

ALTER TABLE Products SET (lock_escalation = disable)

(4) 禁止页锁,并允许索引上的行锁(这意味着您不能对索引进行碎片整理,但您仍然可以重建它们):

ALTER INDEX [<YourIndex>] ON Product WITH (allow_row_locks = on, allow_page_locks = off)
于 2013-02-25T18:31:52.110 回答
1

首先,除了独占锁之外,您无法对这些删除语句使用任何锁。Sql Server 忽略了您的隔离级别和NOLOCK提示:

(nolock) 只适用于SELECT语句。

两个建议:

将您的非聚集索引更改instance为聚集索引。但是,只有在您可以更改NEWID()NEWSEQUENTIALID().

其次,不要执行delete删除超过 10 小时的记录...考虑实施滚动分区delete这将消除因清理与您的其他操作引起的任何争用。

于 2013-02-25T19:04:14.107 回答