昇順の主要な問題-「静止」というブランドの主要な列-SQL Server


9

私はデータベースで実行速度の遅いクエリを調査しており、これが古典的な昇順キー問題であると結論付けました。新しい行がほぼ常に挿入され、DBから最新のデータを引き出すための特定のSQLが30分ごとに実行されるため、30分ごとに統計を更新する最初のオプションは、リソースを浪費する可能性があるようです。

したがって、私はトレースフラグ2389を調べましたが、これは原則的には役立つはずですが、先行列を昇順としてブランド化する必要があり、トレースフラグ2388を使用して(PK)インデックス統計を確認すると、先行列が実際に定常としてブランド化されます-同時に更新される他のテーブルのいくつかのPKインデックスのためです。

ここに画像の説明を入力してください

Stationaryのブランド化の結果に関するガイダンスはそれほど多くないようですが、KB2952101は、挿入の90%未満が古い最大値よりも大きい場合、それはStationaryとして分類されると述べています。すべての挿入は新しい送信であり、最初の列はbigint IDENTITY列であるため、挿入の100%は以前の最大値より大きくなければなりません。

それで、私の質問は、明らかに昇順であるのに、なぜ列がステーショナリーとしてブランド化されるのでしょうか?

毎日実行中のSQLでこの問題を解決するための以前の試み(これは非常にうまく機能しました)により、このテーブルの統計を毎晩更新するジョブがセットアップされました。更新ではFULLSCANが実行されないため、サンプリングされたスキャンで新しい行が欠落することがあり、常に昇順で表示されるとは限りませんか?

これに影響を与える可能性があると私が考えることができる他の唯一のことは、特定の期間を超えて行を削除する舞台裏でアーカイブジョブが実行されていることです。これはブランディングに影響を与える可能性がありますか?

サーバーはSQL Server 2012 SP1です。

更新:別の日、別の統計情報の更新-同じ静止したブランド。前回の統計更新以降、28049の新しい挿入がありました。各行には、挿入されたときのタイムスタンプがあるため、timestamp <'20161102'であるテーブルからmax(id)を選択すると23313455が得られます。

これらの違いは28049の新しい挿入です。ご覧のように、すべての新しい挿入には新しい昇順キーが(期待どおりに)与えられています。これは、先頭の列を固定ではなく昇順としてブランド化する必要があることを示しています。

同じ期間に、アーカイブジョブによって213,629行が削除されました(古いデータは徐々に消去されます)。行数の削減が定常的なブランディングに貢献する可能性はありますか?私はこれを以前にテストしたことがあり、それが何かの違いをもたらすようには見えませんでした。

更新2:別の日、別の統計が更新され、列に昇順のフラグが付けられます!これに影響する削除に関する理論に従って、私は削除と比較して挿入である更新のパーセンテージをチェックしました、そして昨日の13%は挿入でしたが、過去2日間の挿入は約12%を占めました。それが決定的なものになるとは思いません。

興味深いことに、このメインテーブルに挿入された各行に対して平均4行が挿入され、同時に統計が更新される関連テーブルで、IDENTITY PK列はまだ静止していますか?

更新3:週末に追加の挿入物を取得します。今朝、リーディングコラムはステーショナリーに戻りました。前回の統計更新では、46840の挿入と34776の削除しかありませんでした。

繰り返しになりますが、興味深いことに、上記で説明した関連テーブルには、昇順というブランドの主要な列があります。これを説明できるドキュメントはありませんか?

更新4:約1週間が経過しました。アーカイブジョブによりバックログがクリアされたため、挿入される行数の約3分の2を一貫して削除しています。統計は、すべて同じように比例して更新されているにもかかわらず、関連するテーブル全体で混合結果を示しています。1つは定常を示し、2つは上昇を示しています。


今回のケースでは、すべての挿入の値がヒストグラムの最高値を超えているため、列にステーショナリーのブランドを付けるべきではないため、フラグを試していません。これは、SQL Serverが私が本当に望んでいる列をランダムにブランド化しているように見える理由の説明です。ありがとう。
Nik

回答:


3

Stationaryのブランド化の結果に関するガイダンスはそれほど多くないようですが、KB2952101は、挿入の90%未満が古い最大値よりも大きい場合、それはStationaryとして分類されると述べています。すべての挿入は新しい送信であり、先頭の列は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%が挿入されています。削除によって悲しみが生じているようです。この時点で、統計オブジェクトを昇順でヒットさせ、更新しないことでフリーズさせることをお勧めします。
Sean Gallardy-退職ユーザー2016年

私はあなたがしたことを再現してみましたが、最終的に10行を追加して1000を削除し、統計を更新してから統計を表示しましたが、それでも昇順で表示されます:最後の更新以降の挿入:10、最後の更新以降の削除:1000、主要な列タイプ:昇順。なぜあなたに別の結果が出るのか分かりませんか?調査結果が正しい場合は、最適な結果が得られない場合があり、アーカイブのバックログが解消されたら、もう一度お試しください。
Nik

0

私の推定では、サーバー自体で主要なキー列を生成していない限り、個々のクライアントで生成されることに依存して小さなポットホールに陥ることがあります。

また、トレースフラグ2371を試しましたか。

TF 2371はここに記載されています

KBのタイトルは「SQL ServerでのAutostat(AUTO_UPDATE_STATISTICS)の動作の制御」です。KBは2754171です。

新しいデータが統計に反映されない実際の影響をリストアップしておけば、非常に役立ちます。

間違ったインデックスが選択されました。そして、もしそうなら、あなたは私たちのためにインデックスとその主キーをリストアップできますか?

また、統計の日付が付けられたときに生成された計画を、適時の日付に対して共有してもらえますか。2つを比較したいと思います。

私の考えでは、SQL Cost Based Optimizer(Rules and Costing)の決定は非常に適切です。このような難解な領域の外。

これが特殊なケースである場合、詳しい説明が役立つ場合があり、接続アイテムを開くことを正当化します。

余談ですが、私の控えめな意見では、ベンダーにアドホックSQLよりもSPを使用させる方が全体的に大きなメリットがあります。


ありがとう、IDはすべてSQL Serverによって作成されます。フラグ2371は統計の更新をより頻繁にするだけだと理解しています。brentozar.com/archive/2016/03/…のテーブル、テーブルサイズ(1400万行)、および毎日の挿入数(28K行)から判断すると、統計は4日ごとにしか更新されないため、新しいデータの抽出は、ほとんどの場合、新しいデータを知りません。私が調べたクエリは問題ではありません。知りたい主要な列をSQL Serverがどのようにブランド化するかを理解しているからです。再度、感謝します。
Nik、2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.