注意:这是Stack Overflow Teams网站上的问题重新发布,以吸引更多的受众
我有一个包含数百万条记录的事务日志表。链接到这些日志的许多数据项可能每个项都有超过10万行。
当日志表中存在1000多个项目时,如果用户尝试删除某个项目,我必须显示警告。
我们已确定1000条日志表示该项目正在使用
如果我尝试简单地查询表以查找日志行总数,则查询将花费很长时间执行:
SELECT COUNT(1)
FROM History
WHERE SensorID IN (SELECT Id FROM Sensor WHERE DeviceId = 96)
有没有一种更快的方法来确定实体是否具有超过1000条日志记录?
注意:历史记录表在SensorId
列上有一个索引。
答案 0 :(得分:3)
使用Count而不是返回所有行并检查记录计数是正确的,但是我们仍然要求数据库引擎在所有行中进行搜索。
如果要求不是返回最大行数,而是确定行数是否大于 X ,那么我要做的第一个改进就是返回只是表格中的前 X 行。
因此,如果 X 为1000,则无需更改应用程序逻辑,您仍然可以确定999个日志和1000多个日志之间的差异
我们只需更改现有查询,然后选择 TOP(X)行而不是计数,然后返回该结果集的计数,只需选择主键或唯一索引列即可我们仅检查索引,而不检查基础表存储。
select count(Id) FROM (
SELECT TOP(1000) // limit the seek that the DB engine does to the limit
Id // Further constrain the seek to just the indexed column
FROM History
where SensorId IN ( // this is the same filter condition as before, just re-formatted
SELECT Id
FROM Sensor
WHERE DeviceId = 96)
) as trunk
将此查询更改为前10,000个仍可提供亚秒级的响应,但是 X = 100,000时,该查询花费的时间几乎与原始查询一样长
如果所讨论的表具有较高的事务处理速率,并且执行时间的主要原因是由于锁争用引起的等待,那么对于这种类型的问题还有另一种看似“银弹”的方法。
如果您怀疑锁是问题所在,并且可以接受包括未提交的行的计数响应,则可以使用WITH(NOLOCK)
表提示来允许查询在READ UNCOMMITED
事务中有效运行隔离级别。
的讨论很好
SELECT COUNT(1) FROM History WITH (NOLOCK)
WHERE SensorId IN (SELECT Id FROM Sensor WHERE DeviceId = 96)
尽管强烈建议不要这样做,但这是可以轻松允许使用NOLOCK的一个很好的例子,这甚至很有意义,因为删除之前的计数将考虑正在积极添加到日志计数中的另一个用户或操作。 / p>
经过多次试验,当查询1000或10K行时, select with count 解决方案仍然比使用
NOLOCK
表提示更快。NOLOCK
不过提供了一次机会,可以以最小的更改执行相同的查询,同时仍能及时返回。带有
NOLOCK
的select的性能仍将随着基础结果集中行数的增加而提高,而具有最高而没有order by子句的select的性能则随着应该保持不变。