sql >> データベース >  >> RDS >> Sqlserver

大きなテーブルのSQLServer統計を更新する方法

    前回の記事では、データベース統計、その重要性、および統計を更新する必要がある理由について簡単に説明しました。さらに、統計を更新するSQLServerメンテナンスプランを作成するためのステップバイステップのプロセスを示しました。この記事では、次の問題について説明します。1.T-SQLコマンドを使用して統計を更新する方法。 2. T-SQLを使用して頻繁に更新されるテーブルを識別する方法、および頻繁に挿入/更新/削除されるデータでテーブルの統計を更新する方法。

    T-SQLを使用した統計の更新

    T-SQLスクリプトを使用して統計を更新できます。 T-SQLまたはSQLServerManagement Studioを使用して統計を更新する場合は、ALTERデータベースが必要です。 データベースに対する権限。特定のテーブルの統計を更新するには、T-SQLコードの例を参照してください。

    UPDATE STATISTICS <schema_name>.<table_name>.

    OrderLinesの統計を更新する例を考えてみましょう。 WideWorldImportersの表 データベース。次のスクリプトはそれを行います。

    UPDATE STATISTICS [Sales].[OrderLines]

    特定のインデックスの統計を更新する場合は、次のスクリプトを使用できます。

    UPDATE STATISTICS <schema_name>.<table_name> <index_name>

    IX_Sales_OrderLines_Perf_20160301_02の統計を更新する場合 OrderLinesのインデックス テーブルでは、次のスクリプトを実行できます:

    UPDATE STATISTICS [Sales].[OrderLines] [IX_Sales_OrderLines_Perf_20160301_02]

    データベース全体の統計を更新することもできます。テーブルが少なく、データ量が少ない非常に小さなデータベースがある場合は、データベース内のすべてのテーブルの統計を更新できます。次のスクリプトを参照してください:

    USE wideworldimporters 
    go 
    EXEC Sp_updatestats

    頻繁に挿入/更新/削除されたデータを含むテーブルの統計を更新する

    大規模なデータベースでは、統計ジョブのスケジューリングが複雑になります。特に、インデックスのメンテナンスの実行、統計の更新、およびその他のメンテナンスタスクを実行する時間が数時間しかない場合はなおさらです。大規模なデータベースとは、数千のテーブルを含み、各テーブルに数千の行を含むデータベースを意味します。たとえば、Xという名前のデータベースがあります。このデータベースには数百のテーブルがあり、各テーブルには数百万の行があります。また、頻繁に更新されるテーブルはごくわずかです。他のテーブルはめったに変更されず、それらに対して実行されるトランザクションはほとんどありません。前に述べたように、データベースのパフォーマンスを最高の状態に保つには、テーブルの統計が最新である必要があります。そこで、Xデータベース内のすべてのテーブルの統計を更新するSQLメンテナンスプランを作成します。 SQL Serverがテーブルの統計を更新するとき、パフォーマンスの問題につながる可能性のある大量のリソースを使用します。そのため、何百もの大きなテーブルの統計を更新するには長い時間がかかり、統計が更新されている間、データベースのパフォーマンスは大幅に低下します。このような状況では、頻繁に更新されるテーブルの統計のみを更新することを常にお勧めします。次の動的管理ビューを使用して、時間の経過に伴うデータ量または行数の変化を追跡できます。1. sys.partitions テーブル内の行の総数に関する情報を提供します。 2. sys.dm_db_partition_stats パーティションごとの行数とページ数に関する情報を提供します。 3. sys.dm_db_index_physical_stats 行数とページ数に関する情報に加えて、インデックスの断片化などに関する情報を提供します。データ量に関する詳細は重要ですが、データベースアクティビティの全体像を把握することはできません。たとえば、ほぼ同じ数のレコードを持つステージングテーブルをテーブルから削除したり、毎日テーブルに挿入したりできます。そのため、行数のスナップショットは、テーブルが静的であることを示しています。追加および削除されたレコードの値が大きく異なり、データ分散が大幅に変わる可能性があります。この場合、SQL Serverで統計を自動的に更新すると、統計は無意味になります。したがって、テーブルへの変更の数を追跡することは非常に便利です。これは、次の方法で実行できます。1. rowmodctr sys.sysindexes2の列。modified_count sys.system_internals_partition_columns3の列。modification_counter sys.dm_db_stats_propertiesの列したがって、前に説明したように、データベースメンテナンスの時間が限られている場合は、データ変更の頻度が高いテーブル(挿入/更新/削除)の統計のみを更新することを常にお勧めします。これを効率的に行うために、「アクティブな」テーブルの統計を更新するスクリプトを作成しました。このスクリプトは、次のタスクを実行します。•必要なパラメーターを宣言します。• #tempstatisticsという名前の一時テーブルを作成します。 テーブル名、スキーマ名、データベース名を保存するには• #tempdatabaseという名前の別のテーブルを作成します データベース名を保存します。まず、次のスクリプトを実行して2つのテーブルを作成します。

    DECLARE @databasename VARCHAR(500) 
    DECLARE @i INT=0 
    DECLARE @DBCOunt INT 
    DECLARE @SQLCOmmand NVARCHAR(max) 
    DECLARE @StatsUpdateCOmmand NVARCHAR(max) 
    
    CREATE TABLE #tempstatistics 
      ( 
         databasename VARCHAR(max), 
         tablename    VARCHAR(max), 
         schemaname   VARCHAR(max) 
      ) 
    
    CREATE TABLE #tempdatabases 
      ( 
         databasename VARCHAR(max) 
      ) 
    
    INSERT INTO #tempdatabases 
                (databasename) 
    SELECT NAME 
    FROM   sys.databases 
    WHERE  database_id > 4 
    ORDER  BY NAME

    次に、whileループを記述して、すべてのデータベースを反復処理し、200を超える変更カウンターを持つテーブルのリストを #tempstatisticsに挿入する動的SQLクエリを作成します。 テーブル。データの変更に関する情報を取得するには、 sys.dm_db_stats_propertiesを使用します 。次のコード例を調べてください:

    SET @DBCOunt=(SELECT Count(*) 
                        FROM   #tempdatabases) 
          WHILE ( @i < @DBCOunt ) 
            BEGIN 
                DECLARE @DBName VARCHAR(max) 
                SET @DBName=(SELECT TOP 1 databasename 
                             FROM   #tempdatabases) 
                SET @SQLCOmmand= '     use [' + @DBName + '];     select 
    distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter       FROM [' + @DBName+ '].sys.objects AS obj     inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id   INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id    CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like 
    ''sys%'')a' 
        INSERT INTO #tempstatistics 
                    (databasename, 
                     tablename, 
                     schemaname) 
        EXEC Sp_executesql 
          @SQLCOmmand

    次に、最初のループ内に2番目のループを作成します。フルスキャンで統計を更新する動的SQLクエリを生成します。以下のコード例を参照してください:

    DECLARE @j INT=0 
        DECLARE @StatCount INT 
    
        SET @StatCount =(SELECT Count(*) 
                         FROM   #tempstatistics) 
    
        WHILE @J < @StatCount 
          BEGIN 
              DECLARE @DatabaseName_Stats VARCHAR(max) 
              DECLARE @Table_Stats VARCHAR(max) 
              DECLARE @Schema_Stats VARCHAR(max) 
              DECLARE @StatUpdateCommand NVARCHAR(max) 
    
              SET @DatabaseName_Stats=(SELECT TOP 1 databasename 
                                       FROM   #tempstatistics) 
              SET @Table_Stats=(SELECT TOP 1 tablename 
                                FROM   #tempstatistics) 
              SET @Schema_Stats=(SELECT TOP 1 schemaname 
                                 FROM   #tempstatistics) 
              SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats 
                                     + '].[' + @Schema_Stats + '].[' + @Table_Stats 
                                     + '] with fullscan' 
              EXEC Sp_executesql 
                @StatUpdateCommand 
              SET @[email protected] + 1 
              DELETE FROM #tempstatistics 
              WHERE  databasename = @DatabaseName_Stats 
                     AND tablename = @Table_Stats 
                     AND schemaname = @Schema_Stats 
          END 
        SET @[email protected] + 1 
        DELETE FROM #tempdatabases 
        WHERE  databasename = @DBName 
    END

    スクリプトの実行が完了すると、すべての一時テーブルが削除されます。

    SELECT * 
        FROM   #tempstatistics 
        DROP TABLE #tempdatabases 
        DROP TABLE #tempstatistics

    スクリプト全体は次のように表示されます。

    --set count on     
    CREATE PROCEDURE Statistics_maintenance 
    AS 
      BEGIN 
          DECLARE @databasename VARCHAR(500) 
          DECLARE @i INT=0 
          DECLARE @DBCOunt INT 
          DECLARE @SQLCOmmand NVARCHAR(max) 
          DECLARE @StatsUpdateCOmmand NVARCHAR(max) 
          CREATE TABLE #tempstatistics 
            ( 
               databasename VARCHAR(max), 
               tablename    VARCHAR(max), 
               schemaname   VARCHAR(max) 
            ) 
          CREATE TABLE #tempdatabases 
            ( 
               databasename VARCHAR(max) 
            ) 
          INSERT INTO #tempdatabases 
                      (databasename) 
          SELECT NAME 
          FROM   sys.databases 
          WHERE  database_id > 4  
          ORDER  BY NAME 
          SET @DBCOunt=(SELECT Count(*) 
                        FROM   #tempdatabases) 
          WHILE ( @i < @DBCOunt ) 
            BEGIN 
                DECLARE @DBName VARCHAR(max) 
                SET @DBName=(SELECT TOP 1 databasename 
                             FROM   #tempdatabases) 
                SET @SQLCOmmand= '     use [' + @DBName + '];     select 
    distinct ''' + @DBName+ ''', a.TableName,a.SchemaName from (SELECT obj.name as TableName, b.name as SchemaName,obj.object_id, stat.name, stat.stats_id, last_updated, modification_counter       FROM [' + @DBName+ '].sys.objects AS obj     inner join ['+ @DBName + '].sys.schemas b on obj.schema_id=b.schema_id   INNER JOIN [' + @DBName+ '].sys.stats AS stat ON stat.object_id = obj.object_id    CROSS APPLY [' + @DBName+'].sys.dm_db_stats_properties(stat.object_id, stat.stats_id) AS sp WHERE modification_counter > 200 and obj.name not like ''sys%''and b.name not like 
    ''sys%'')a' 
        INSERT INTO #tempstatistics 
                    (databasename, 
                     tablename, 
                     schemaname) 
        EXEC Sp_executesql 
          @SQLCOmmand 
    
        DECLARE @j INT=0 
        DECLARE @StatCount INT 
    
        SET @StatCount =(SELECT Count(*) 
                         FROM   #tempstatistics) 
    
        WHILE @J < @StatCount 
          BEGIN 
              DECLARE @DatabaseName_Stats VARCHAR(max) 
              DECLARE @Table_Stats VARCHAR(max) 
              DECLARE @Schema_Stats VARCHAR(max) 
              DECLARE @StatUpdateCommand NVARCHAR(max) 
    
              SET @DatabaseName_Stats=(SELECT TOP 1 databasename 
                                       FROM   #tempstatistics) 
              SET @Table_Stats=(SELECT TOP 1 tablename 
                                FROM   #tempstatistics) 
              SET @Schema_Stats=(SELECT TOP 1 schemaname 
                                 FROM   #tempstatistics) 
              SET @StatUpdateCommand='Update Statistics [' + @DatabaseName_Stats 
                                     + '].[' + @Schema_Stats + '].[' + @Table_Stats 
                                     + '] with fullscan' 
              EXEC Sp_executesql 
                @StatUpdateCommand 
              SET @[email protected] + 1 
              DELETE FROM #tempstatistics 
              WHERE  databasename = @DatabaseName_Stats 
                     AND tablename = @Table_Stats 
                     AND schemaname = @Schema_Stats 
          END 
        SET @[email protected] + 1 
        DELETE FROM #tempdatabases 
        WHERE  databasename = @DBName 
    END 
        SELECT * 
        FROM   #tempstatistics 
        DROP TABLE #tempdatabases 
        DROP TABLE #tempstatistics 
    END

    スケジュールされた時間にスクリプトを実行するSQLServerエージェントジョブを作成することにより、このスクリプトを自動化することもできます。このジョブを自動化するためのステップバイステップの説明を以下に示します。

    SQLジョブの作成

    まず、プロセスを自動化するSQLジョブを作成しましょう。これを行うには、SSMSを開き、目的のサーバーに接続してSQL Serverエージェントを展開し、ジョブを右クリックします。 新しいジョブを選択します 。 新しい仕事 ダイアログボックスで、名前に目的の名前を入力します 分野。 次に、[手順]をクリックします 新しいジョブの左側のパネルにあるメニューオプション ダイアログボックスをクリックし、[新規]をクリックします 手順で 窓。 新しいジョブステップ 開いたダイアログボックスで、ステップ名に目的の名前を入力します 分野。次に、 Transact-SQLスクリプト(T-SQL)を選択します タイプ ドロップダウンボックス。次に、 DBAToolsを選択します データベース内 ドロップダウンボックスを使用して、コマンドテキストボックスに次のクエリを入力します。

    EXEC Statistics_maintenance

    ジョブのスケジュールを構成するには、[スケジュール]をクリックします。 新しいジョブのメニューオプション ダイアログボックス。 新しいジョブスケジュール ダイアログボックスが開きます。 名前 フィールドに、目的のスケジュール名を入力します。この例では、このジョブを毎晩午前1時に実行する必要があるため、発生で実行します。 頻度のドロップダウンボックス セクションで、毎日を選択します 。 で1回発生 毎日の頻度のフィールド セクションに01:00:00と入力します。 OKをクリックします 新しいジョブスケジュールを閉じる ウィンドウをクリックし、[ OK ]をクリックします 再び新しい仕事で ダイアログボックスを閉じます。それでは、このジョブをテストしてみましょう。 SQL Serverエージェントで、 Update_Statistics_Dailyを右クリックします。 。 ジョブが正常に実行されると、次のウィンドウが表示されます。

    概要

    この記事では、次の問題について説明しました。1.T-SQLスクリプトを使用してテーブルの統計を更新する方法。 2.データ量の変化とデータ変化の頻度に関する情報を取得する方法。 3.アクティブなテーブルの統計を更新するスクリプトを作成する方法。 4.スケジュールされた時間にスクリプトを実行するSQLServerエージェントジョブを作成する方法。


    1. TimescaleDBバックアップをクラウドに保存するためのヒント

    2. SQLiteOpenHelper:物理デバイスで呼び出されないonCreate()メソッド

    3. postgresqlでのn番目のパーセンタイル計算

    4. PythonのSSHトンネリングを介したPostgreSQLデータベースへの接続