5

SQLServer2005データベースに頻繁に使用されるテーブルがあります。手持ちの在庫情報があります。倉庫から1時間ごとに更新を受け取り、過去数年間、テーブルを切り捨てて情報を更新するルーチンを実行してきました。これには数秒しかかからず、今まで問題はありませんでした。現在、この情報を照会するシステムを使用している人がはるかに多く、その結果、プロセスのブロックが原因で多くのタイムアウトが発生しています。

... それで ...

私たちは選択肢を調査し、問題を軽減するためのアイデアを思いつきました。

  1. 2つのテーブルがあります。表A(アクティブ)および表B(非アクティブ)。
  2. アクティブなテーブル(テーブルA)を指すビューを作成します。
  3. このテーブル情報(4つのオブジェクト)を必要とするすべてのものは、ビューを通過する必要があります。
  4. 時間単位のルーチンは、非アクティブなテーブルを切り捨て、最新の情報で更新してから、非アクティブなテーブルを指すようにビューを更新して、アクティブなテーブルにします。
  5. このルーチンは、アクティブなテーブルを判別し、基本的にそれらの間でビューを切り替えます。

これの何が問題になっていますか?クエリの途中でビューを切り替えると問題が発生しますか?これは機能しますか?

専門知識をありがとうございます。

追加情報

  • ルーチンは、多くのステップを実行し、最終的に問題のテーブルを切り捨て/更新するSSISパッケージです。

  • ブロッキングプロセスは、このテーブルをクエリする他の2つのストアドプロシージャです。

4

10 に答える 10

7

スナップショットアイソレーションの使用を検討しましたか。それはあなたがあなたのSSISのもののために大きな太ったトランザクションを始めて、それでもテーブルから読むことを可能にするでしょう。

このソリューションは、テーブルを切り替えるよりもはるかにクリーンなようです。

于 2009-05-20T15:32:54.820 に答える
2

これは間違った方法で行われていると思います。テーブルを更新すると、テーブルをロックする必要がありますが、そのロックをページごと、または行ごとに制限することもできます。

私はテーブルを切り捨てずに補充することを検討します。それは常にそれを読もうとするユーザーの邪魔になります。

テーブルを置き換えるのではなく更新した場合は、これを別の方法で制御できます。読み取りユーザーはテーブルをブロックしないでください。楽観的な読み取りを回避できる可能性があります。

読み取りSQLビューステートメントにwith(nolock)ヒントを追加してみてください。テーブルが定期的に更新されている場合でも、非常に大量のユーザーに読んでもらうことができるはずです。

于 2009-05-20T14:45:17.770 に答える
2

SSISを使用していることを読んでください

TableDiferenceコンポーネントは、http ://www.sqlbi.eu/Home/tabid/36/ctl/Det​​ails/mid/374/ItemID/0/Default.aspxから使用できます。

代替テキスト
(出典:sqlbi.eu

このようにして、変更を1つずつテーブルに適用できますが、もちろん、これははるかに遅くなり、テーブルのサイズによってはサーバーでより多くのRAMが必要になりますが、ロックの問題は完全に修正されます。

于 2009-05-20T15:29:41.830 に答える
2

個人的には、テーブルに対してバッチプロセスを実行するために常にダウンタイムを導入する場合は、ビジネス/データアクセス層でユーザーエクスペリエンスを管理する必要があると思います。そのテーブルへの接続を監視し、バッチ処理を制御するテーブル管理オブジェクトを導入します。

新しいバッチデータの準備ができると、管理オブジェクトはすべての新しいクエリ要求を停止し(おそらくキューに入れますか?)、既存のクエリを完了させ、バッチを実行してから、クエリ用にテーブルを再度開きます。管理オブジェクトは、UIレイヤーが解釈できるイベント(BatchProcessingEvent)を発生させて、テーブルが現在使用できないことをユーザーに通知できます。

私の$0.02、

ネイト

于 2009-05-20T14:50:56.057 に答える
1

切り捨て操作ではなく、トランザクションを使用して情報を更新してみませんか。

切り捨てはログに記録されないため、トランザクションで実行できません。

操作がトランザクションで行われる場合、既存のユーザーは影響を受けません。

これがどのように行われるかは、テーブルのサイズやデータがどの程度急激に変化するかなどによって異なります。あなたがより詳細を与えるならば、おそらく私はさらにアドバイスすることができます。

于 2009-05-20T14:46:08.580 に答える
1

考えられる解決策の 1 つは、テーブルの更新に必要な時間を最小限に抑えることです。

最初にステージング テーブルを作成して、ウェアハウスからデータをダウンロードします。

最終テーブルで「挿入、更新、および削除」を行う必要がある場合

フィナーレのテーブルが次のようになっているとします。

Table Products:
    ProductId       int
    QuantityOnHand  Int

また、倉庫から QuantityOnHand を更新する必要があります。

まず、次のようなステージング テーブルを作成します。

Table Prodcuts_WareHouse
    ProductId       int
    QuantityOnHand  Int

そして、次のような「アクション」テーブルを作成します。

Table Prodcuts_Actions
    ProductId       int
    QuantityOnHand  Int
    Action          Char(1)

更新プロセスは次のようになります。

1.テーブルProdcuts_WareHouseを切り捨てます

2.テーブルProdcuts_Actionsを切り捨てます

3. Prodcuts_WareHouse テーブルに倉庫からのデータを入力します。

4. Prodcuts_Actions テーブルに次の情報を入力します。

インサート:

INSERT INTO Prodcuts_Actions (ProductId, QuantityOnHand,Action)
SELECT     SRC.ProductId, SRC.QuantityOnHand, 'I' AS ACTION
FROM         Prodcuts_WareHouse AS SRC LEFT OUTER JOIN
                      Products AS DEST ON SRC.ProductId = DEST.ProductId
WHERE     (DEST.ProductId IS NULL)

削除します

INSERT INTO Prodcuts_Actions (ProductId, QuantityOnHand,Action)
SELECT     DEST.ProductId, DEST.QuantityOnHand, 'D' AS Action
FROM         Prodcuts_WareHouse AS SRC RIGHT OUTER JOIN
                      Products AS DEST ON SRC.ProductId = DEST.ProductId
WHERE     (SRC.ProductId IS NULL)

アップデート

INSERT INTO Prodcuts_Actions (ProductId, QuantityOnHand,Action)
SELECT     SRC.ProductId, SRC.QuantityOnHand, 'U' AS Action
FROM         Prodcuts_WareHouse AS SRC INNER JOIN
                      Products AS DEST ON SRC.ProductId = DEST.ProductId AND SRC.QuantityOnHand <> DEST.QuantityOnHand

これまで、あなたはファイナル テーブルをロックしていませんでした。

5.トランザクションで最終テーブルを更新します。

BEGIN TRANS

DELETE Products FROM Products INNER JOIN
Prodcuts_Actions ON Products.ProductId = Prodcuts_Actions.ProductId
WHERE     (Prodcuts_Actions.Action = 'D')

INSERT INTO Prodcuts (ProductId, QuantityOnHand)
SELECT ProductId, QuantityOnHand FROM Prodcuts_Actions WHERE Action ='I';

UPDATE Products SET QuantityOnHand = SRC.QuantityOnHand 
FROM         Products INNER JOIN
Prodcuts_Actions AS SRC ON Products.ProductId = SRC.ProductId
WHERE     (SRC.Action = 'U')

COMMIT TRAN

上記のすべてのプロセスを使用すると、更新するレコードの量を必要最小限に抑えることができるため、更新中に最終テーブルがロックされる時間を最小限に抑えることができます。

最終ステップでトランザクションを使用することさえできないため、コマンド間でテーブルが解放されます。

于 2009-05-20T15:13:41.363 に答える
1

Enterprise Edition の SQL Server を自由に使用できる場合は、SQL Server パーティショニング テクノロジを使用することをお勧めします。

現在必要なデータを「ライブ」パーティション内に配置し、更新されたバージョンのデータを「セカンダリ」パーティション内に配置することができます (これはクエリには使用できず、データの管理には使用できません)。

データが 'Secondary' パーティションにインポートされると、'LIVE' パーティションを OUT に、'Secondary' パーティションを IN に即座に切り替えることができるため、ダウンタイムが発生せず、ブロックも発生しません。

切り替えが完了したら、不要になったデータを切り捨てることができます。新しいデータ (以前はセカンダリ パーティション) のユーザーに悪影響を与えることはありません。

インポート ジョブを実行する必要があるたびに、プロセスを繰り返す/逆にするだけです。

SQL Server のパーティショニングの詳細については、次を参照してください。

http://msdn.microsoft.com/en-us/library/ms345146(SQL.90).aspx

または、私に尋ねることもできます:-)

編集:

余談ですが、ブロッキングの問題に対処するために、SQL Server 行のバージョン管理テクノロジを使用できます。

http://msdn.microsoft.com/en-us/library/ms345124(SQL.90).aspx

于 2009-05-20T15:17:06.550 に答える
0

使用率の高いシステムでこれを行っており、問題は発生していません。ただし、すべてのデータベースと同様に、それが役立つことを確認する唯一の方法は、dev で変更を加えてから負荷テストを行うことです。SSIS パッケージが他に何をするかわからない場合でも、ブロックが発生する可能性があります。

于 2009-05-20T15:13:22.893 に答える
0

テーブルがそれほど大きくない場合は、アプリケーションでデータを短時間キャッシュすることができます。ブロッキングを完全になくすことはできませんが、更新が発生したときにテーブルがクエリされる可能性は低くなります。

于 2009-05-20T15:46:43.887 に答える
0

変更されたランドスケープの一部であるように見えるため、ブロックしているプロセスの分析を行うことはおそらく理にかなっています。表示されているブロックを作成するには、不適切に作成されたクエリが 1 つだけ必要です。適切に記述されていないクエリを除いて、テーブルには 1 つ以上のカバリング インデックスが必要であり、それらのクエリを高速化し、既に動作しているコードを再設計する必要なく元に戻すことができます。

お役に立てれば、

明細書

于 2009-05-20T17:10:56.180 に答える