升序关键问题-品牌为“ Stationary”的前导列-SQL Server


9

我一直在研究数据库中运行缓慢的查询,并得出结论,这是一个经典的升序关键问题。由于几乎总是不断地插入新行,并且每隔30分钟就会运行一条用于从数据库中提取最新数据的SQL代码,因此每30分钟更新一次统计信息的第一种选择听起来像是在浪费资源。

因此,我研究了跟踪标志2389,它在原则上应该有帮助,但是这要求Leading列被标记为Ascending,并且当我使用Trace Flag 2388检查(PK)索引统计信息时,我发现该领先列实际上是品牌为固定-与同时更新其他表上的多个PK索引相同。

在此处输入图片说明

关于文具品牌的结果似乎没有太多指导,但是我确实发现KB2952101表示如果少于90%的插入物大于旧的最大值,它将被归类为文具。我们所有的插入内容都是新提交的内容,前导列是bigint IDENTITY列,因此100%的插入内容应大于先前的最大值。

所以我的问题是,当列显然是升序的时候,为什么要将该列打上固定的名称?

较早尝试解决某些日常运行的SQL(确实运行良好)的问题,导致设置了一项工作来每晚更新此表的统计信息。该更新不执行FULLSCAN,所以采样扫描有时可能会丢失新行,因此它并不总是以升序显示吗?

我唯一想到的可能会影响此的原因是,我们有一个后台运行的存档作业,删除了一定期限内的行。这会对品牌产生影响吗?

该服务器是SQL Server 2012 SP1。

更新:另一天,另一项统计信息更新-相同的固定品牌。自从之前的统计信息更新以来,已经有28049个新插入内容。每行都有插入时间的时间戳,因此如果我从timestamp <'20161102'的表中选择max(id),则会得到23313455类似地,如果我对今天的统计信息进行更新,则会得到23341504。

它们之间的区别是28049个新插入物,因此,如您所见,所有新插入物都被赋予了新的升序键(如预期的那样),这表明前导柱应被标记为升序而不是固定的。

在同一时期,我们的归档作业删除了213,629行(我们正在慢慢清除旧数据)。行数减少是否有可能为固定品牌做出贡献?我之前对此进行了测试,但看起来没有任何区别。

更新2:另一天,另一项统计信息更新,该列现在标记为升序!根据有关影响删除的理论,我检查了插入与删除相比更新的百分比,昨天有13%是插入,而前两天插入约占12%。我认为这没有任何决定性的意义。

有趣的是,相关表平均插入该主表中的每一行都会插入4行,并同时更新其统计信息,其IDENTITY PK列是否仍为Stationary !?

更新3:在周末,我们会获得更多插入。今天早上,领导小组回到了固定式。在上次统计信息更新中,我们有46840次插入,而只有34776次删除。

再次,有趣的是,我上面提到的相关表现在将其前导列标记为Ascending。没有文档可以解释这一点吗?

更新4:大约一周前,归档作业已经清除了积压的订单,因此我们一直在删除大约三分之二的要插入的行。这些统计数据在相关表中显示出混合的结果,其中一个显示固定,而两个显示上升,尽管它们均按相似的比例进行更新。


在我们的例子中,所有插入的值都超过直方图中的最大值,因此该列不应贴上Stationary品牌,因此我没有尝试过该标志。这说明了为什么SQL Server似乎会随机标记我真正想要的列。谢谢。
Nik

Answers:


3

关于文具品牌的结果似乎没有太多指导,但是我确实找到了KB2952101,它说如果少于90%的插入物大于旧的最大值,它将被归类为文具。我们所有的插入内容都是新提交的内容,前导列是bigint IDENTITY列,因此100%的插入内容应大于先前的最大值。

所以我的问题是,当列显然是升序的时候,为什么要将该列打上固定的名称?

如果您已经说过,如果10%或更多的刀片没有上升,它将被冠以固定商标。如果100%的插入内容如您所说...那么您可能不会遇到此问题,当然您要删除它,然后它才能恢复为未知状态。

这是您的问题的复制品:

use master;
go
-- create a database for this to test
create database AscendingKey;
go

use AscendingKey;
go
-- create a test table
create table dbo.AscendingKeyTableTest
(
    SomeData        char(100) default('A'),
    AscendingKey    bigint not null,
);
go

-- insert some dummy data
set nocount on
go

declare @i int = 1

while(@i <= 1000)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- create stats on the ascendingkey column
create statistics AscendingKeyStats on dbo.AscendingKeyTableTest(AscendingKey);
go

-- look at the stats
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- unknown

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);

-- now insert a few more ascending
declare @i int;
declare @j int = 1;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

while(@j <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+@j);
    set @j += 1
end
go

-- update the stats
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

-- check again
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
-- ascending!
-- we hit the 3x stats updates to have it 'learn'

-- what happens if we insert more than 10% that isn't ascending
declare @i int = 1;

while(@i <= 10)
begin
    insert into AscendingKeyTableTest(AscendingKey) VALUES (@i);
    set @i += 1
end
go

-- still says ascending... but...
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- what if we update again?
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go
-- stationary
dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- get it back to ascending
declare @i int;

SELECT @i = max(ascendingkey) from dbo.AscendingKeyTableTest;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+1);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+2);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;

insert into AscendingKeyTableTest(AscendingKey) VALUES (@i+3);
update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go

-- what about the deletes?
delete from AscendingKeyTableTest where AscendingKey % 3 = 0
go

update statistics ascendingkeytabletest(ascendingkeystats) with fullscan;
go

dbcc traceon(2388);
dbcc show_statistics('dbo.ascendingkeytabletest', ascendingkeystats);
dbcc traceoff(2388);
go
-- back to unknown

-- cleanup
use master
go

drop database AscendingKey
go

我使用与上面相同的脚本进行了快速测试,但只运行了插入和删除部分。如果删除的行数量远大于插入的行数量,它将恢复为固定状态(大约10%)。在更新的数据中,您已经插入了大约10%的所有数据更改-删除操作似乎使您感到悲伤。在这一点上,我建议让stats对象命中升序,然后通过不更新它来冻结它。
Sean Gallardy-退休用户

我尝试重新创建完成的操作,最终又增加了10行并删除了1000行,更新了统计信息,然后显示统计信息,但仍然显示升序:自上次更新以来插入:10,自上次更新以来删除:1000,前导列类型: 上升。不确定为什么我会给您不同的结果吗?如果您的发现是正确的,那可能只是现在忍受不到最佳结果的情况,然后当我们的存档积压工作清除后,再试一次。
Nik

0

据我估计,除非您在服务器本身上生成前导键列,否则依靠单个客户端上生成的键列,您可能会陷入困境。

另外,您是否尝试过跟踪标志2371。

TF 2371记录在这里

该知识库的标题为“在SQL Server中控制自动状态(AUTO_UPDATE_STATISTICS)行为”。KB为2754171。

如果您要为我们列出新数据的实际影响而不及时将其纳入统计数据,这将非常有用。

选择了错误的索引。而且,如果可以的话,您能为我们列出索引及其主键吗?

另外,能否请您分享统计数据过时时所生成的计划以及它们何时及时生成。我想将两者进行比较。

我的想法是,基于SQL Cost的优化器(规则和成本计算)决策非常好。在像这样的深奥地区之外。

如果这是特例,则更多说明可能会有所帮助,并有理由打开一个连接项。

顺便说一句,以我的拙见,让供应商使用SP比使用即席SQL具有更大的总体收益。


谢谢,这些ID都是由SQL Server创建的。我了解标记2371只会使统计信息更新更加频繁。根据brentozar.com/archive/2016/03/…上的表格,我们的表格大小(1400万行)和每日插入次数(2.8万行)来判断,统计信息仍只会每4天左右更新一次,因此新数据的提取大部分时间将不知道新数据。我关注的查询不是问题,它理解SQL Server如何为我想知道的领先品牌打上烙印。再次感谢。
Nik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.