web-dev-qa-db-ja.com

時間の経過とともにクエリのパフォーマンスを予測する合理的な方法

処理済みファイルのデータを保存するために使用しているSQL Server 2012データベースがあります。フォルダーからデータを読み取り、pythonで処理して、結果をデータベースに保存します。

ETLプロセスで最初に行うことの1つは、ファイルが既に処理されているかどうかを確認することです。私たちは単に次のことを行います:

SELECT id FROM table1 WHERE basename = <basename>

結果がある場合はファイルをスキップし、結果がない場合はファイルを処理します。現在、このクエリは500万レコードで250ミリ秒かかります。 basename列には非クラスター化インデックスが既にあります。

1か月あたり約10万〜20万件のレコードが追加されます。ファイルはバッチで取得します。したがって、2kファイルが表示され、2時間後に別の2kファイルが表示される可能性があります。場合によっては10kファイルを取得することもあれば、4kファイルしか取得しないこともあります。

他のすべての変数を同じに保つと、テーブルに1500〜2000万のレコードを挿入して何が起こるかを確認する以外に、このクエリでパフォーマンス(クエリに1秒以上かかる)の問題が発生する可能性がある場合に予測するための経験則がありますか?

テーブルDDL:

CREATE TABLE [dbo].[raw_records](
[id] [int] IDENTITY(1,1) NOT NULL,
[basename] [varchar](512) NULL,
[filename] [varchar](1024) NULL,
[file_size] [int] NULL,
[machine] [varchar](10) NULL,
[insert_timestamp] [datetime] NULL,
[raw_xml] [xml] NULL,
[process_status] [varchar](2048) NULL,

PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

インデックス:

CREATE NONCLUSTERED INDEX [basename_index] ON [dbo].[raw_records]
(
    [basename] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO

このテーブルは、作業を始めるずっと前に作成されたので、誰かがfilename 1024を「十分」に保持できる最大長にしただけだと思います。確かに変更可能です。

生成されるファイルには、ファイル名自体にタイムスタンプと一意の情報が含まれます(例:system1_metadata_timestamp.xml)1つの「システム」が同じタイムスタンプのファイルを生成できなかった(または生成してはならない)。

select max(len(basename)), max(len(filename)) from dbo.raw_records;

戻り値:basename-143、filename-168。おそらく、最大260に変更するのが良いでしょう。

process_statusもそれほど長くする必要はないかもしれませんが、処理フェーズからのエラーメッセージを保持するための列があるため、推測するのは妥当だと思います。私はそれにクエリを実行し、最大600文字でした。ただし、通常はその列に対してクエリを実行しません。これは、デバッグのための単なる情報です。

そのようなものをクリーンアップするアプリケーションを調べています。特定の場所ではそれから逃れることができないが、他の場所では残念ながらそれについて多くのことを行うことができない(たとえば、データを抽出するために実際にXML列を取得する必要がある)。この質問は、単に問題のクエリのパフォーマンスを確認し、それが私から離れたくないことから生じたものです。これは、すべてのファイルに対して最初に行われる処理であるため、それが機能しない場合でも、他には何も起こりません。

7
Kevin Vasko

適切なインデックスが存在する場合、一致する行を見つけるのにかかる時間は、メモリ内にインデックス用のスペースがある限り、ほぼ対数的にスケーリングする必要があります。

ベース名は一意である必要があるため、インデックスをUNIQUEにします。そうしないと、ワークフローが無効になり、インデックスがより効率的になります。

CREATE UNIQUE INDEX IX_raw_records_basename
ON dbo.raw_records (basename);

クエリの実行プランをチェックして、インデックスが使用されていることを確認します。

インデックス用にメモリに十分なスペースがあることを確認します。同時実行性が大きな問題にならないと想定すると、非常に多数の行に適しているはずです。

basename列とfilename列の長さを再考します。クエリオプティマイザーは、クエリを実行するために割り当てる必要があるメモリの量を計算するときにその長さを使用するためです。たとえば、basename列が20文字を超えることはなく、512文字として定義されている場合、SELECT basename FROM dbo.raw_records;のメモリ許可は実際に必要な量の25.6倍になります。列の長さは実際、ほとんどの人が理解するよりもはるかに重要です。

クエリをSELECT 1 FROM table1 WHERE basename = <basename>に変更して、idも必要ないようにすることもできます。これは、その存在を確認するだけなので、本当に必要なことだけを行ってください。あなたの質問に表示するインデックスはそのためにうまく機能するようです。

12
Max Vernon

それが何であるかのように扱います...ステージングテーブル。 ETLプロセスを完了するのに十分な長さでデータファイルをそこに配置し、テーブルを切り捨てるファイル名と日付を「FileProcessLog」テーブルに保管して、処理されたファイルの処理日時を記録できるようにします。完了するまでにかかった時間。実際の生ファイルをデータベースに長期間保持することは、何の問題もありません...本当に毎晩のバックアップにテラバイトのアーカイブファイルを含めたいですか?

0
Jason A. Long