4

私は以下のような奇妙な状況を経験します:

「Table1」という名前のデータベースに巨大なテーブルがあります。次に、次のコードを使用してまったく同じテーブルを複製します。

Select * into Table2 from Table1

その後、クエリのパフォーマンスが劇的に異なることがわかりました。

Select count (distinct ID) from Table1 完了するまでに約2分かかります。(古いテーブル)

その間、 Select count (distinct ID) from Table2 完了するのに約10秒かかります(新しいテーブル)

ちなみに、「selectinto」の後にデータがnewtableで並べ替えられていたことがわかりました。さらに、新しいテーブルを「選択」する前に、Table1(古いテーブル)に列が追加されました(つまり、テーブルを変更し、col1をcol2として追加します)。

では、これはどのように起こりますか?

(注:質問の元のバージョンでは、新しいテーブルは遅いテーブルであると述べられていました。これはエラーでした。また、Table1のデータ操作については言及されていませんでした)


詳細情報の要求への応答

これは、セバスチャンのコードからの結果です。

SELECT  QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + '.' + QUOTENAME(t.name) tbl,
        s.name stats_name,
        cols.cols,
        t.create_date table_date,
        STATS_DATE(s.object_id, s.stats_id) AS statistics_date,
        s.auto_created,
        s.user_created,
        s.no_recompute,
        s.has_filter,
        s.filter_definition
FROM    sys.tables t
LEFT OUTER JOIN sys.stats s
        ON s.object_id = t.object_id
OUTER APPLY (
              SELECT  STUFF((SELECT ',' + c.name
                             FROM   sys.stats_columns sc
                             JOIN   sys.columns c
                                    ON sc.column_id = c.column_id
                                       AND sc.object_id = c.object_id
                             WHERE  sc.object_id = s.object_id
                                    AND sc.stats_id = s.stats_id
                             ORDER BY sc.stats_column_id
                      FOR   XML PATH(''),
                                TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') cols
            ) cols
--Update Table Name(s) here:      
WHERE   t.OBJECT_ID IN ( OBJECT_ID('[Sales].[SpecialOffer]'),
        OBJECT_ID('[Sales].[SalesOrderDetail]') );

SELECT  name,
        compatibility_level,
        is_auto_close_on,
        is_auto_shrink_on,
        state_desc,
        is_auto_create_stats_on,
        is_auto_update_stats_on,
        is_auto_update_stats_async_on
FROM sys.databases
WHERE database_id = DB_ID();

実際、新しいテーブルを別のデータベースにコピーします。そして、テーブル名は実際にはID2000という名前です

上の画像は「Table1」(データベース1)を参照しています。下の画像は「Table2」(データベース2)を参照しています。


XMLコードが長すぎるので、Hamletのアドバイスに従った代替のプリントアウトを次に示します。SET SHOWPLAN_ALL ON GO すべてのXMLコードを貼り付ける代わりに使用 します。お役に立てば幸いです。

赤い色は「表1」の計画を表し、黒い色は「表2」を表します。画像のテキストは少し小さいですが、このページサイズを大きくしてズームインすると、単に拡大されます。

どうもありがとうございます!! 図1


の結果SELECT * FROM sys.dm_db_index_physical_stats(db_id(),object_id('YourTable'),NULL,NULL,'Detaile‌​d')

実際、2つのテーブルの間には大きな違いがあります。同様に、赤い色は「表1」を示し、別の色は「表2」を示します。

この問題は非常に厄介で、すべてのテーブルを再構築するかどうかを自問し続けるので、私は夢中になります。:( ここに画像の説明を入力してください

実際には非常に奇妙です。record_countが異なることに注意してください。ただし、で再確認する select COUNT (ID) from id2000と(つまり、このテーブルの合計データ行を計算します)、両方の結果は2324798であり、これはTable_2のrecord_countです。

さらに、「Table2」は「select * into」ステートメントによって作成されました。両方とも同じである必要があると思いますが、今は混乱しています。

ここに画像の説明を入力してください 上記の表は、Sebastianコードのコード(Running stat)の結果です。


の結果SELECT * FROM sys.dm_db_index_physical_stats(db_id(),object_id('YourTable'),NULL,NULL,'Detaile‌​d')

実際、2つのテーブルの間には大きな違いがあります。同様に、赤い色は「表1」を示し、別の色は「表2」を示します。

この問題は非常に厄介で、すべてのテーブルを再構築するかどうかを自問し続けるので、私は夢中になります。:( ここに画像の説明を入力してください

実際には非常に奇妙です。record_countが異なることに注意してください。ただし、で再確認する select COUNT (ID) from id2000と(つまり、このテーブルの合計データ行を計算します)、両方の結果は2324798であり、これはTable_2のrecord_countです。

さらに、「Table2」は「select * into」ステートメントによって作成されました。両方とも同じである必要があると思いますが、今は混乱しています。

4

3 に答える 3

3

さて、古いテーブルが新しいテーブルではなく遅いテーブルであることがわかったので、すべてが原因である非常に大量の転送されたレコードを示しています。

転送されたレコードを削除するには、次のクエリを使用できます。

ALTER TABLE dbo.Table2 REBUILD;

ヒープに列を追加すると、ほとんどの場合、すべての行が頻繁に移動し、転送されるレコードの量が非常に多くなります。forwarded_records_countDMVによって返される列にsys.dm_db_index_physical_statsは、転送の数が表示されます。この場合、ほとんどすべての行が表示されます。

ASELECT * INTOは転送ポインタをコピーせず、代わりに再編成します。したがって、あなたが見たパフォーマンスの違い。

フォワードについて話している間、ほとんどの場合、テーブルにクラスター化されたインデックスを設定することをお勧めします。これにより、このような問題を回避できます。

あなたの場合、ID列はクラスター化された主キーの候補のようです(一意の場合)が、ここで推奨事項を提供するには、モデルについて詳しく知る必要があります。

于 2012-12-26T15:31:51.283 に答える
1

もう1つ試してみてください:これを実行して、テキストとクエリ結果を投稿してください。いつものように、Table1とTable2を実際の名前に置き換えてください。この場合、データベース名も置き換える必要があります。

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO
SELECT COUNT(DISTINCT ID) FROM DB1.dbo.Table1
GO
SELECT COUNT(DISTINCT ID) FROM DB2.dbo.Table2
GO
SELECT COUNT(DISTINCT ID) FROM DB1.dbo.Table1
GO
SELECT COUNT(DISTINCT ID) FROM DB2.dbo.Table2
GO
SELECT COUNT(DISTINCT ID) FROM DB1.dbo.Table1
GO
SELECT COUNT(DISTINCT ID) FROM DB2.dbo.Table2
GO
SET STATISTICS TIME OFF;
SET STATISTICS IO OFF;
GO
SELECT * FROM sys.dm_db_index_operational_stats(DB_ID('DB1'),OBJECT_ID('DB1.dbo.Table1'),NULL,NULL);
SELECT * FROM sys.dm_db_index_operational_stats(DB_ID('DB2'),OBJECT_ID('DB2.dbo.Table2'),NULL,NULL);
于 2012-12-26T12:19:30.360 に答える
0

これは古い統計が原因だと思います。しかし、私たちはあなたの環境についてもう少し情報が必要です。これらの2つのクエリを実行して、結果を投稿できますか?提供されている2つのテーブルではなく、2つのテーブルの名前を使用してください。

SELECT  QUOTENAME(OBJECT_SCHEMA_NAME(t.object_id)) + '.' + QUOTENAME(t.name) tbl,
        s.name stats_name,
        cols.cols,
        t.create_date table_date,
        STATS_DATE(s.object_id, s.stats_id) AS statistics_date,
        s.auto_created,
        s.user_created,
        s.no_recompute,
        s.has_filter,
        s.filter_definition
FROM    sys.tables t
LEFT OUTER JOIN sys.stats s
        ON s.object_id = t.object_id
OUTER APPLY (
              SELECT  STUFF((SELECT ',' + c.name
                             FROM   sys.stats_columns sc
                             JOIN   sys.columns c
                                    ON sc.column_id = c.column_id
                                       AND sc.object_id = c.object_id
                             WHERE  sc.object_id = s.object_id
                                    AND sc.stats_id = s.stats_id
                             ORDER BY sc.stats_column_id
                      FOR   XML PATH(''),
                                TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') cols
            ) cols
--Update Table Name(s) here:      
WHERE   t.OBJECT_ID IN ( OBJECT_ID('[Sales].[SpecialOffer]'),
        OBJECT_ID('[Sales].[SalesOrderDetail]') );

SELECT  name,
        compatibility_level,
        is_auto_close_on,
        is_auto_shrink_on,
        state_desc,
        is_auto_create_stats_on,
        is_auto_update_stats_on,
        is_auto_update_stats_async_on
FROM sys.databases
WHERE database_id = DB_ID();
于 2012-12-25T17:06:53.223 に答える