SQL Server 2005 データベースにテーブルを作成し、集計値と計算値を入力しました。目的は、データベースへのすべての呼び出しで大規模な結合とグループ化を回避することです。このテーブルを 1 時間ごとに更新したいのですが、Web サイトに負荷がかかっているときにこれを行う最善の方法がわかりません。1 つのトランザクションですべてのレコードを削除してテーブルを再作成すると、うまくいくでしょうか、それともデッドロックやその他の問題が潜んでいるのでしょうか?
4 に答える
いくつかのプロジェクトでこれを行った方法は、異なるスキーマでテーブルの 2 つのコピーを使用することです。次のようなものです:
CREATE SCHEMA fake WITH AUTHORIZATION dbo;
CREATE SCHEMA standby WITH AUTHORIZATION dbo;
GO
CREATE TABLE dbo.mySummary(<...columns...>);
CREATE TABLE fake.mySummary(<...columns...>);
GO
次に、偽のテーブルを切り捨てて再入力するストアド プロシージャを作成し、トランザクションでオブジェクトをスキーマ間で移動します。
CREATE PROCEDURE dbo.SwapInSummary
AS
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE fake.mySummary;
INSERT fake.mySummary(<...columns...>)
SELECT <expensive query>;
BEGIN TRANSACTION;
ALTER SCHEMA standby TRANSFER dbo.mySummary;
ALTER SCHEMA dbo TRANSFER fake.mySummary;
ALTER SCHEMA fake TRANSFER standby.mySummary;
COMMIT TRANSACTION;
END
GO
これはおそらく、新しいデータが更新されるまでユーザーを待機させ、読み取りの途中でユーザーを中断させることができない最短の時間です。(NOLOCK にはあまり望ましくない代替手段となる多くの問題がありますが、確かにコーディングは簡単です。) 簡潔/明確にするために、エラー処理などを省略しました。スクリプトを使用してデータベースを同期する場合は、両方のテーブルで制約やインデックスなどに同じ名前を付けてください。そうしないと、半分の時間で同期が取れなくなります。手順の最後に、新しい fake.MySummary テーブルを TRUNCATE できますが、スペースがあればそこにデータを残しておき、常に以前のバージョンと比較できるようにします。
SQL Server 2005 より前は、トランザクション内で sp_rename を使用してまったく同じことを達成していましたが、ジョブでこれを行っているため、スキーマに切り替えてよかったと思っています。 SQL Server エージェントの履歴ログをアップします。
負荷の重さに応じて、インデックス付きビューを作成することもできます。これは良い選択かもしれません
@temp テーブル変数にデータを作成することにしました。次に、ロールアップ ID を一致する一時テーブルにコピーします。最後に、@temp テーブルに基づいてロールアップ テーブルの行を追加、更新、および削除します。
これは、データベース内の関係と、データベースに対して実行するクエリによって異なります。
古いデータを許容できるサマリー テーブルの場合は、NOLOCK 結合ヒントを使用して、ロックなしで SELECT を実行するクエリを使用してデータを入力できます。注: NOLOCK ヒントの使用は、結果が確実な場合にのみ行う必要があります。
多くの場合、負荷を軽減するためにインデックスを再調整する余地があります。