SQL Server计数很慢

Adi*_*Adi 35 sql sql-server sql-server-2005 count sql-server-2008

计算具有大量数据的表可能非常慢,有时需要几分钟; 它还可能在繁忙的服务器上生成死锁.我想显示实际值,NOLOCK不是一个选项.

我使用的服务器是SQL Server 2005或2008 Standard或Enterprise - 如果重要的话.我可以想象SQL Server维护每个表的计数,如果没有WHERE子句,我可以很快得到这个数字,对吗?

例如:

SELECT COUNT(*) FROM myTable
Run Code Online (Sandbox Code Playgroud)

应立即返回正确的值.我是否需要依赖统计数据进行更新?

Aar*_*and 58

非常近似(忽略任何飞行中的交易)将是:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  WHERE t.name = N'myTable'
  AND s.name = N'dbo'
  AND p.index_id IN (0,1);
Run Code Online (Sandbox Code Playgroud)

这将返回更快,更快COUNT(*),并且如果你的表变化足够快,它实际上并不那么准确 - 如果你的表在你开始你的COUNT(和锁被采取)和它被返回(当锁定时)之间发生了变化已经被释放,所有等待的写入事务现在都被允许写入表格,是否更有价值?我不这么认为.

如果你想要计算表的某个子集(比方说WHERE some_column IS NULL),你可以在该列上创建一个过滤索引,并根据它是异常还是规则来构造where子句,这取决于它是异常还是规则(所以在较小的集合上创建过滤的索引).所以这两个指标之一:

CREATE INDEX IAmTheException ON dbo.table(some_column)
  WHERE some_column IS NULL;

CREATE INDEX IAmTheRule ON dbo.table(some_column)
  WHERE some_column IS NOT NULL;
Run Code Online (Sandbox Code Playgroud)

然后你可以用类似的方式得到计数:

SELECT SUM(p.rows) FROM sys.partitions AS p
  INNER JOIN sys.tables AS t
  ON p.[object_id] = t.[object_id]
  INNER JOIN sys.schemas AS s
  ON s.[schema_id] = t.[schema_id]
  INNER JOIN sys.indexes AS i
  ON p.index_id = i.index_id
  WHERE t.name = N'myTable'
  AND s.name = N'dbo'
  AND i.name = N'IAmTheException' -- or N'IAmTheRule'
  AND p.index_id IN (0,1);
Run Code Online (Sandbox Code Playgroud)

如果你想知道相反的情况,你只需从上面的第一个查询中减去.

  • @Adi对sys.partitions的查询花了很长时间?我觉得很难相信. (2认同)
  • 此答案中的查询此时似乎对Azure Sql起作用.我正在一个P2数据库中测试一个200M +行的表,每分钟大量插入大约5K新行.此答案中的查询立即返回,一个朴素的SELECT COUNT(*)大约需要一分钟(它使用索引扫描).两者都返回相同的数字. (2认同)

Naj*_*ero 10

("大量数据"有多大? - 应该首先对此进行评论,但也许下面的执行官已经帮助你了解)

如果我在静态机器上运行查询(意味着没有其他人在很长一段时间内读取/写入/更新都很烦人,那么争用不是问题)表格在我的开发机器上在15秒内有2亿行和COUNT(*)甲骨文).考虑到纯数据量,这仍然很快(至少对我来说)

如你所说NOLOCK不是一个选项,你可以考虑

exec sp_spaceused 'myTable'
Run Code Online (Sandbox Code Playgroud)

同样.

但这与NOLOCK几乎相同(忽略争用+删除/更新afaik)


pcd*_*dev 8

我已经使用 SSMS 十多年了,直到去年才发现它可以快速轻松地为您提供此信息,这要归功于这个答案

  1. 从数据库树中选择“Tables”文件夹(对象资源管理器)
  2. 按 F7 或选择“视图” > “对象资源管理器详细信息”以打开“对象资源管理器详细信息”视图
  3. 在此视图中,您可以右键单击列标题来选择要查看的列,包括使用的表空间、使用的索引空间和行数: 在此输入图像描述

请注意,Azure SQL 数据库对此的支持充其量似乎有点不稳定 - 我的猜测是来自 SSMS 的查询超时,因此每次刷新它只返回少数表,但突出显示的表似乎总是返回。