web-dev-qa-db-ja.com

ファクトテーブルのパフォーマンスを向上させる

ファクトテーブルCardTransactionFactがあります

テーブル構造

_TABLE [dbo].[CardTransactionFact]
    [CardTransactionID] [int] IDENTITY(1,1) NOT NULL,
    [TransactionTerminalID] [int] NOT NULL,
    [SourceAccountTypeID] [int] NULL,
    [DestinationAccountTypeID] [int] NULL,
    [RimNo] [varchar](15) NULL,
    [CaptureCodeID] [int] NOT NULL,
    [RoutingCodeID] [int] NOT NULL,
    [ProcessingCodeID] [int] NOT NULL,
    [ActionCodeID] [int] NOT NULL,
    [NetworkCodeID] [int] NOT NULL,
    [ProductCodeID] [int] NOT NULL,
    [AcquiringCountryCodeID] [int] NOT NULL,
    [IssuingCountryCodeID] [int] NOT NULL,
    [TransactionCurrencyCodeID] [int] NOT NULL,
    [AmountBD] [decimal](18, 3) NOT NULL,
    [LocalCurrencyCodeID] [int] NOT NULL,
    [CardIssuerBank] [int] NOT NULL,
    [CardTypeID] [int] NOT NULL,
    [SuspectTransactionFlag] [char](1) NOT NULL,
    [ReversalTransactionFlag] [char](1) NOT NULL,
    [LocalTransactionDateKey] [int] NOT NULL,
    [LocalTransactionHourKey] [int] NOT NULL,
    [BBKRole] [char](1) NOT NULL,
    [AmountRangeKey] [int] NULL,
    [CustomerKey] [int] NULL
_

サイズ:11GB行数:56,959,828


現在、このテーブルにアクセスすることは非常に困難になっています。単純なSelect count(*) from CardTransactionFactの実行には数時間かかります。

表のほとんどの列は単なる整数であるため、インデックスを作成しませんでした。

このテーブルを改善し、このテーブルへのクエリの速度を上げるために私は何をすべきだと思いますか

  1. どの列にインデックスを付ける必要があるのか​​、その理由
  2. テーブルを分割するのは良い考えですか
  3. その他の提案
2
AmmarR

ここでは多くの問題がありますが、ありがたいことに修正できることがたくさんあります。

問題:

  • ヒープがあります。これは非常に断片化されており、ページは82GBのデータファイル全体に分散している可能性があります。断片化のチェックに関するガイダンスについては、 sys.dm_db_index_physical_stats を参照してください。
  • メモリーは6GBしかないのですが、運が良ければ、バッファープールで4GBを使用できるかもしれません。
  • 行間を読んで、あなたは犬の遅いSATAスピナードライブを使用しています。
  • テーブルのスキャンには、その犬の低速ドライブ全体で11GBのランダムIOが必要であり、バッファプールを完全に3回チャーンします。

修正:

  • テーブルにクラスター化されたインデックスを作成します。 CardTransactionIdは、現在唯一の賢明な選択のように見えます。
  • あなたは必死にメモリが必要です。 128GBは、82GBのデータウェアハウスに適しています。
  • ひどく不十分なIOがあります。 SSDは最も安価で最速の修正です。

11GBは6GBに収まりません、それは本当にとても簡単です。非常に大まかな見積もりでは、テーブルが約150万ペー​​ジを占めることを示唆しています。100IOPSの場合、ディスクからの読み取りには約4時間かかります(最悪の場合、100%ランダム読み取り、先読みなしなど)。

9

クエリを置き換える

SELECT COUNT(*) FROM CardTransactionFact

以下で

SELECT Rows FROM SYS.PARTITIONS WHERE OBJECT_ID = OBJECT_NAME('CardTransactionFact')

絶対必要です Clustered Indexテーブルに。 DBCC CONTIGを実行して、ヒープテーブルのフラグメンテーションを確認します

Create Clustered INDEX IX_Column on TableName(COLUMNNAME)

テーブルで発生する問題は、断片化の問題です。 DELETES、INSERTS、UPDATESなどの実行されるアクティビティによっては、ヒープテーブルとクラスター化テーブルが断片化する可能性があります。これの多くは、アクティビティと、クラスタ化されたインデックスに使用されるキー値に依存します。

  1. ヒープテーブルでINSERTSのみが発生している場合、新しいデータのみが書き込まれるため、テーブルは断片化されません。
  2. クラスター化インデックスキーがID値などのシーケンシャルであり、INSERTSしかない場合も、新しいデータは常にクラスター化インデックスの最後に書き込まれるため、これは断片化されません。
  3. ただし、テーブルがヒープテーブルまたはクラスター化テーブルのいずれかであり、INSERT、UPDATE、およびDELETEが多数ある場合、データページは非常に断片化される可能性があります。これにより、スペースが無駄になり、クエリを満たすために読み取るデータページが追加されます。テーブルがヒープとして作成される場合、SQLServerは新しいデータページが書き込まれる場所を強制しません。新しいデータが書き込まれるときはいつでも、このデータは常にテーブルの最後またはこのテーブルに割り当てられている次の使用可能なページに書き込まれます。データが削除されると、データページの空き容量が増えますが、新しいデータは常に次の使用可能なページに書き込まれるため、再利用されません。クラスタ化インデックスでは、インデックスキーに応じて、空き領域が存在する既存のページに新しいレコードが書き込まれる場合や、新しいデータを挿入するためにページを複数のページに分割する必要がある場合があります。削除が発生すると、ヒープの場合と同じ問題が発生しますが、空き領域がある既存のページの1つにデータを挿入する必要がある場合は、この空き領域を再度使用できます。

インデックス再構築前の統計

enter image description here

DBCC CONTIGを再度実行して、ヒープテーブルのフラグメンテーションを確認します

インデックス再構築後の統計

インデックスクエリを再構築してインデックスを削除します

ALTER INDEX ALL 
ON TableName
REBUILD WITH 
(
     FILLFACTOR = 80, 
     SORT_IN_TEMPDB = ON,
     STATISTICS_NORECOMPUTE = ON
);

enter image description here

参照

2
testing

インデックス作成とパーティショニングの両方が非常に役立ちます。ただし、どのインデックスとパーティションの分割方法は、それらに対して実行するクエリに大きく依存します。

インデックスやパーティショニングがない場合、クエリオプティマイザーはすべてのクエリの完全なテーブルを読み取る必要があります。

パーティショニング部分について、データを複数のパーティションに簡単に分離するために使用できる論理列はありますか?そして、この列をほとんどのクエリのwhere句に追加することは可能ですか?

0
Edward Dortland