pok*_*oke 8 index sql-server sql-server-2008-r2 transaction
我偶然发现了从根本上改变了我对事务和锁定的知识的情况(虽然我知道的不多),我需要帮助来理解它。
假设我有一张这样的表:
CREATE TABLE [dbo].[SomeTable](
[Id] [bigint] IDENTITY(1,1) NOT NULL,
[SomeData] [varchar](200) NOT NULL,
[Moment] [datetime] NOT NULL,
[SomeInt] [bigint] NOT NULL
) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)
我运行这个“在事务中插入 1000 行”查询:
BEGIN TRAN t1
DECLARE @i INT = 0
WHILE @i < 1000
BEGIN
SET @i = @i + 1
INSERT INTO [SomeTable] ([SomeData] ,Moment, SomeInt)
VALUES (CONVERT(VARCHAR(255), NEWID()), getdate(), @i)
WAITFOR DELAY '00:00:00:010'
END
COMMIT TRAN t1
Run Code Online (Sandbox Code Playgroud)
在此事务运行时,我正在执行一个简单的选择:
SELECT Id, Moment, SomeData, SomeInt FROM [SomeTable]
Run Code Online (Sandbox Code Playgroud)
并非总是可以重现它(显然取决于时间),但有时选择查询将在插入事务完成后返回少于 1000 行。在我的无知中,我相信 select 将始终返回 1000 行(鉴于隔离级别为 Read Committed),但显然我误解了事务和锁定的工作方式。
但是,如果我在 Id 列(生成聚集索引)上放置一个主键,只要我尝试过,select 查询就会返回所有 1000 行。以其他方式放置索引,在复合键上使用聚集索引,在其他一些列上使用非聚集索引,可能会再次导致返回的行数少于我的预期。
所以,我有这些问题:
提前致谢。
Mar*_*ith 12
在运行您的代码几次后,我还没有设法重现这一点。
不过,我认为当稍后的行插入到文件中的较早页面时,它必须发生。
所以操作顺序是(例如)
该表包括 10 页。默认情况下,前 8 个页面将从混合区分配,然后分配一个统一区。也许在您的情况下,在使用混合范围之前,文件中有可用的空间可用于免费统一范围。
重现问题后,您可以通过在不同窗口中运行以下命令来测试该理论,并查看原始数据中缺失的行是否SELECT
都出现在此结果集的开头。
SELECT [SomeData],
Moment,
SomeInt,
file_id,
page_id,
slot_id
FROM [SomeTable]
/*Undocumented - Use at own risk*/
CROSS APPLY sys.fn_PhysLocCracker(%% physloc %%)
ORDER BY page_id, SomeInt
Run Code Online (Sandbox Code Playgroud)
针对索引表的操作将按索引键顺序而不是分配顺序进行,因此不会受此特定情况的影响。
可以对索引执行分配顺序扫描,但仅当表足够大并且隔离级别未提交读取或持有表锁时才考虑。
因为读提交通常会在读取数据后立即释放锁,所以对索引的扫描可能会读取两次行或根本不读取行(如果索引键被并发事务更新,导致行向前或向后移动)有关此类问题的更多讨论,请参阅Read Committed Isolation Level。
顺便说一下,我最初设想的索引情况是索引位于相对于插入顺序增加的列之一(Id、Moment、SomeInt 中的任何一个)。然而,即使聚集索引是随机SomeData
的,问题仍然不会出现。
我试过
DBCC TRACEON(3604, 1200, -1) /*Caution. Global trace flag. Outputs lock info
on every connection*/
SELECT TOP 2 *,
%%LOCKRES%%
FROM [SomeTable] WITH(nolock)
ORDER BY [SomeData];
SELECT *,
%%LOCKRES%%
FROM [SomeTable]
ORDER BY [SomeData];
/*Turn off trace flags. Doesn't check whether or not they were on already
before we started, with TRACEOFF*/
DBCC TRACEOFF(3604, 1200, -1)
Run Code Online (Sandbox Code Playgroud)
结果如下
第二个结果集包括所有 1,000 行。锁定信息显示,即使24c910701749
在释放锁定时它被阻止等待锁定资源,它也不会从该点继续扫描。相反,它立即释放该锁并在新的第一行上获取行锁。
归档时间: |
|
查看次数: |
6325 次 |
最近记录: |