web-dev-qa-db-ja.com

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

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

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

enter image description here

Stationaryのブランディングにどのような結果をもたらすかについては、あまりガイダンスはないようですが、 KB2952101 は、挿入の90%未満が古い最大値よりも大きい場合、それは文房具として分類。すべての挿入は新しい送信であり、先頭の列はbigint IDENTITY列であるため、挿入の100%は以前の最大値より大きくなければなりません。

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

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

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

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

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

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

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

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

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

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

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

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

8
Nik

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
3
Sean Gallardy

私の推定では、サーバー自体で主要なキー列を生成しているのでない限り、個々のクライアントで生成されている列に依存する小さな穴に入る可能性があります。

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

TF 2371は文書化されています ここ

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

時間の経過とともに統計に反映されない新しいデータの実際の影響をリストアップすると、非常に役立ちます。

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

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

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

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

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

0
Daniel Adeniji