如何从当前INSERT的表中选择COUNT?

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).

Dav*_*idG 6

简短的回答:你不能这样做.

更长的答案:单个INSERT语句是一个原子操作.因此,查询已插入所有行或未插入任何行.因此,您无法计算它的进展程度.

甚至更长的答案:马丁史密斯已经给你一个实现你想要的方法.当然,你是否还想这样做取决于你.就个人而言,如果你真的需要跟踪这样的事情的进展,我仍然希望插入可管理的批次.所以我会将INSERT重写为多个较小的语句.根据您的实施情况,这可能是一件微不足道的事情.


Mar*_*ith 4

如果您使用的是 SQL Server 2016,实时查询统计功能可以让您实时查看插入的进度。

下面的屏幕截图是将 1000 万行插入到具有聚集索引和单个非聚集索引的表中时拍摄的。

它显示聚集索引上的插入已完成 88%,随后将进行排序运算符,以便在插入 NCI 之前将值按非聚集索引键顺序排列。这是一个阻塞运算符,在消耗所有输入行之前排序无法输出任何行,因此左侧的运算符已完成 0%。

在此输入图像描述

关于你的问题NOLOCK

测试是微不足道的

连接1

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)

连接2

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-SSCH-M(模式修改)锁。大概您还在同一事务中对表执行了一些 DDL(例如,可能在同一事务中创建了它)

对于大型插入的用例,在飞行中的近似结果就可以了,我通常只是sysindexes如上所示进行轮询以从元数据中检索计数,而不是实际计算行数(可以使用未弃用的替代 DMV

当插入具有广泛的更新计划时,您甚至可以看到它以这种方式依次插入到各个索引中。

如果表是在插入事务内创建的,则该sysindexes查询仍会阻塞,因为OBJECT_ID无论隔离级别有效,该函数都不会基于未提交的数据返回结果。有时可以通过从sys.tableswith获取 object_id 来解决这个问题nolock