web-dev-qa-db-ja.com

sys.objectsの統計を更新する

直接または間接的に任意のレベルで依存するすべてのデータベースオブジェクトを、依存度の高いdbo.tblborderというテーブルに渡すクエリを作成しています。

ただし、この質問は特にクエリのクエリプランに関連しています。クエリプラン(個別の並べ替え演算子で)に2種類の警告が表示されるためです。1つはtempDBへの流出に関するもので、もう1つはデータ型と基数の見積もり。

クエリとクエリプランは、図の後でさらに下にあります。

ご質問

システムオブジェクトを処理しているときに、統計を更新する必要があるオブジェクトを見つけるにはどうすればよいですか?

または、クエリプランでこの警告を回避するにはどうすればよいですか?

そして、データ型変換に関して、これを回避するために私ができることは何ですか、そしてカーディナリティ推定の問題はありますか?

たぶんいくつかのトレースフラグ?

それは600 GBのデータベースです。特定のテーブルに対するすべての依存関係を見つけたいと思います。最初のレベルだけで325のオブジェクトが表示されますが、これは毎日実行するクエリではありません。私はそれらの警告をクリアすることに興味がありますが、それは生と死の問題ではありません。

情報

tempdbの流出に関する警告の最初の画像:

picture of warning on spillage on tempdb

tempdbの流出に関する警告の2番目の画像:

enter image description here

3番目の警告-データ型変換に関連し、カーディナリティの推定に影響する可能性があります

enter image description here

;WITH Radhe AS (

            SELECT DISTINCT 
            s2.object_id, 
            Name=SCHEMA_NAME(S2.schema_id) + '.' + S2.Name, 
            ObjectType = S2.Type,
            DependsOn = s1.object_id,
            DependsOn_Name=SCHEMA_NAME(S1.schema_id) + '.' + S1.Name,  
            0 as Level

            FROM sys.sysdepends DP

            INNER JOIN sys.objects S1 
                    ON S1.object_id = DP.DepID

            INNER JOIN sys.objects S2 
                    ON S2.object_id = DP.ID

            WHERE S1.object_id = OBJECT_ID('DBO.tblborder')

            UNION ALL


            SELECT  
            s2.object_id, 
            Name=SCHEMA_NAME(S2.schema_id) + '.' + S2.Name, 
            ObjectType = S2.Type,
            DependsOn = s1.object_id,
            DependsOn_Name=s1.Name,  
            Level + 1 

            FROM sys.sysdepends DP

            INNER JOIN Radhe S1 
                       ON S1.object_id = DP.ID

            INNER JOIN sys.objects S2 
                       ON S2.object_id = DP.DepID

            WHERE Level < 100
              AND S1.object_id <> S2.object_id
              AND S2.object_id <> OBJECT_ID('DBO.tblborder')

)

SELECT DISTINCT * 
FROM Radhe
ORDER BY LEVEL DESC, DependsOn_Name

これはこのクエリのクエリプランです

統計をこのように更新した後(データベースのシステムテーブルの統計を更新する方法 から ):

DECLARE @TSql NVARCHAR(MAX) = ''
SELECT @TSql = @TSql +  'UPDATE STATISTICS sys.' + o.name + ' WITH FULLSCAN;' + CHAR(13) + CHAR(10)
FROM sys.objects o
WHERE o.type in ('S')
ORDER BY o.name

--Verify/test commands.
PRINT @TSql

Tempdbの漏出に関連する警告はまだ残っていますが、以下の図のように変更されています。

enter image description here

ただし、次の警告については何も言われていないか、対処されていません。

式の型変換(CONVERT(bigint、[Bocss2]。[sys]。[sysobjvalues]。[value]、0))は、クエリプランの選択の "CardinalityEstimate"に影響する可能性があります。式の型変換(CONVERT(bigint、[Bocss2] 。[sys]。[sysobjvalues]。[value]、0))は、クエリプランの選択で「CardinalityEstimate」に影響を与える可能性があります

関連するQ&A データベースのシステムテーブルの統計を更新する方法 は非常に優れていますが、ここでは問題が完全に解決されていないようで、さらにカーディナリティ推定警告。

5

ほとんどの場合、表示される警告はsys.sysdependsビューからのものです。

スクリプトを使用して

EXEC sys.sp_helptext @objname = N'sys.sysdepends'

定義には、たくさんの改宗者やその他のナンセンスが続いています。

CREATE VIEW sys.sysdepends AS  
 SELECT  
  id = object_id,  
  depid = referenced_major_id,  
  number = convert(smallint,  
   case when objectproperty(object_id, 'isprocedure') = 1 then 1 else column_id end),  
  depnumber = convert(smallint, referenced_minor_id),  
  status = convert(smallint, is_select_all * 2 + is_updated * 4 + is_selected * 8),  
  deptype = class,  
  depdbid = convert(smallint, 0),  
  depsiteid = convert(smallint, 0),  
  selall = is_select_all,  
  resultobj = is_updated,  
  readobj = is_selected  
 FROM sys.sql_dependencies  
 WHERE class < 2  
 UNION ALL  
 SELECT  -- blobtype dependencies  
  id = object_id, depid = object_id,  
  number = convert(smallint, column_id), depnumber = convert(smallint, type_column_id),  
  status = convert(smallint, 0), deptype = sysconv(tinyint, 1),  
  depdbid = convert(smallint, 0), depsiteid = convert(smallint, 0),  
  selall = sysconv(bit, 0), resultobj = sysconv(bit, 0), readobj = sysconv(bit, 0)  
 FROM sys.fulltext_index_columns  
 WHERE type_column_id IS NOT NULL  

一方、sys.objectsはかなり単純です。

CREATE VIEW sys.objects AS  
 SELECT name,   
  object_id,  
  principal_id,  
  schema_id,  
  parent_object_id,  
  type,   
  type_desc,   
  create_date,   
  modify_date,  
  is_ms_shipped,  
  is_published,  
  is_schema_published  
 FROM sys.objects$  

Sys.sysdependsのビュー定義は 単独で照会された場合と同じ警告 を引き起こします。

SELECT *
FROM  sys.sysdepends  

一般に、データ型とインデックスを制御し、システムビューまたはテーブルを参照するときにパフォーマンス調整機能を使用する場合は、最初にそれらを一時テーブルにダンプすることをお勧めします。

5
Erik Darling

クエリプランの警告は、クエリが許容レベルで実行されない場合にのみ問題になります。 10ミリ秒で終了するクエリがある場合、警告を表示しないようにするために、プログラマが時間をかけて高速化しようとするのはなぜですか。実際、tempdbに溢れるクエリは警告をスローします。クエリがtempdbにこぼれないシステムに興味があります。

また、tempdbへの流出には、さまざまな原因が考えられます。実際、SQL Serverが故意にtempdbに流出する場合があります。システムによっては、基礎となるテーブルの統計を更新することは、問題に対処するための合理的なステップになる場合があります。ただし、これで問題が解決されるとは限りません。

システムビューを使用する必要があるという事実に夢中になっているようです。それは、ベンダーが提供する、変更できないビューに対するコードを書くようなものだと考えてください。他のクエリに対して使用できるのと同じ最適化手法のほとんどすべてを使用できます。非表示のシステムテーブルにインデックスや統計を作成することはできないと思います。

エリックはすでにデータ型変換警告に関する質問をカバーしているので、他の質問に焦点を当てます。

使用されているシステムオブジェクトを見つける最も簡単な方法は、クエリを実行する前にSET STATISTICS IO, TIME ON;を発行することです。例えば:

SET STATISTICS IO, TIME ON;

SELECT COUNT(*) FROM sys.objects;

-- Table 'sysschobjs'. Scan count 1

UPDATE STATISTICS sys.sysschobjs WITH FULLSCAN;

あなたが経験したように、流出をなくすにはそれで十分ではないかもしれません。ここでの問題は、再帰クエリを記述したことだと思います。 SQL Serverクエリオプティマイザーでは、再帰クエリによって返される行数を正確に推定できない場合がよくあります。私には、これは合理的な制限のようです。モデル化するのが非常に難しいもののように感じます。

おそらく、ここでの問題は、それが再帰クエリであることではありません。流出を解消するために他に何ができるでしょうか?

1。重要な中間結果セットを一時テーブルに入れます

カーディナリティの見積もりは、行がクエリプランを通過するにつれて悪化することがよくあります。クエリの結果の一部を一時テーブルに入れ、その一時テーブルをクエリで参照できる場合があります。一部のクエリでは、小さな結果セットを一時テーブルに入れるだけで、パフォーマンスと見積もりを劇的に向上させることができます。

2。 レガシーCEを試してください

トレースフラグ9481がシステムビューに対するクエリのパフォーマンスを向上させることを確認しました。カーディナリティの見積もりに問題があると思われる場合、それを試すことができます。

3。 SQL Serverをだまして、より大きなクエリメモリ許可を発行します。

SQL Server 2016では、これは新しい MIN_GRANT_PERCENT クエリヒントでかなり簡単です。古いバージョンでは少し難しいです。返される推定行数を増やす論理的に同等のコードを記述する必要があります。

4。最後にソートが必要ないようにクエリを書き直します

これがどれほど難しいかを確認するためにコードを調べたことはありませんが、この提案は自明だと思います。

流出に役立つ他のトレースフラグの観点から、私は トレースフラグ747 しか知りません。

3
Joe Obbish