use*_*188 5 sql sql-server sql-server-2012
嗨,考虑在表TABLE_A上运行INSERT语句,这需要很长时间,我想看看它是如何进展的.
我试过的是打开一个新的会话(SSMS中的新查询窗口),而长时间运行的语句仍在进行中,我运行了查询
SELECT COUNT(1) FROM TABLE_A WITH (nolock)
Run Code Online (Sandbox Code Playgroud)
希望每次运行查询时它都会立即返回行数,但测试结果甚至是(nolock),但它只会在INSERT语句完成后返回.
我错过了什么?我是否也将(nolock)添加到INSERT语句中?或者这是不可能实现的?
(编辑)好的,我找到了我错过的东西.如果您首先使用CREATE TABLE TABLE_A,然后INSERT INTO TABLE_A,则SELECT COUNT将起作用.如果您使用SELECT*INTO TABLE_A FROM xxx,而不首先创建TABLE_A,那么以下内容将不起作用(甚至不是sysindexes).
如果您使用的是 SQL Server 2016,实时查询统计功能可以让您实时查看插入的进度。
下面的屏幕截图是将 1000 万行插入到具有聚集索引和单个非聚集索引的表中时拍摄的。
它显示聚集索引上的插入已完成 88%,随后将进行排序运算符,以便在插入 NCI 之前将值按非聚集索引键顺序排列。这是一个阻塞运算符,在消耗所有输入行之前排序无法输出任何行,因此左侧的运算符已完成 0%。
关于你的问题NOLOCK
测试是微不足道的
USE tempdb
CREATE TABLE T2
(
X INT IDENTITY PRIMARY KEY,
F CHAR(8000)
);
WHILE NOT EXISTS(SELECT * FROM T2 WITH (NOLOCK))
LOOP:
SELECT COUNT(*) AS CountMethod FROM T2 WITH (NOLOCK);
SELECT rows FROM sysindexes WHERE id = OBJECT_ID('T2');
RAISERROR ('Waiting for 10 seconds',0,1) WITH NOWAIT;
WAITFOR delay '00:00:10';
SELECT COUNT(*) AS CountMethod FROM T2 WITH (NOLOCK);
SELECT rows FROM sysindexes WHERE id = OBJECT_ID('T2');
RAISERROR ('Waiting to drop table',0,1) WITH NOWAIT
DROP TABLE T2
Run Code Online (Sandbox Code Playgroud)
use tempdb;
--Insert 2000 * 2000 = 4 million rows
WITH T
AS (SELECT TOP 2000 'x' AS x
FROM master..spt_values)
INSERT INTO T2
(F)
SELECT 'X'
FROM T v1
CROSS JOIN T v2
OPTION (MAXDOP 1)
Run Code Online (Sandbox Code Playgroud)
SELECT允许脏读的查询NOLOCK。它们实际上并不需要任何锁,并且仍然可以被阻止,它们仍然需要SCH-S表上的(架构稳定性)锁(并且在堆上它也将需要hobt锁)。
唯一与 a 不兼容的SCH-S是SCH-M(模式修改)锁。大概您还在同一事务中对表执行了一些 DDL(例如,可能在同一事务中创建了它)
对于大型插入的用例,在飞行中的近似结果就可以了,我通常只是sysindexes如上所示进行轮询以从元数据中检索计数,而不是实际计算行数(可以使用未弃用的替代 DMV)
当插入具有广泛的更新计划时,您甚至可以看到它以这种方式依次插入到各个索引中。
如果表是在插入事务内创建的,则该sysindexes查询仍会阻塞,因为OBJECT_ID无论隔离级别有效,该函数都不会基于未提交的数据返回结果。有时可以通过从sys.tableswith获取 object_id 来解决这个问题nolock。