6

.NET Webアプリケーションに、プラットフォーム上のユーザーがアカウントをクリアする(つまり、すべてのデータを削除する)ことができるルーチンがあります。このルーチンはストアドプロシージャで実行され、基本的に関連するデータテーブルをループして、作成したさまざまなアイテムをすべてクリアします。

ストアドプロシージャは次のようになります。

ALTER procedure [dbo].[spDeleteAccountData](
    @accountNumber varchar(30) ) 
AS
BEGIN
    SET ANSI_NULLS ON ;
    SET NOCOUNT ON;

    BEGIN TRAN  
    BEGIN TRY
        DELETE FROM myDataTable1 WHERE accountNumber = @accountNumber
        DELETE FROM myDataTable2 WHERE accountNumber = @accountNumber
        DELETE FROM myDataTable3 WHERE accountNumber = @accountNumber
        //Etc.........

    END TRY
    BEGIN CATCH
        //CATCH ERROR
    END CATCH

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION; 
SET ANSI_NULLS OFF;
SET NOCOUNT OFF;
END

問題は、場合によっては、テーブルに10,000行を超える可能性があり、手順に最大3〜5分かかる可能性があることです。この期間中、データベース上の他のすべての接続が抑制され、次のようなタイムアウトエラーが発生します。

System.Data.SqlClient.SqlException(0x80131904):タイムアウトが期限切れになりました。操作が完了する前にタイムアウト期間が経過したか、サーバーが応答していません。

パフォーマンスを向上させるために行うことができる一般的な変更はありますか?データベーススキーマの設計に関連する不明な点がたくさんあることを感謝しますが、一般的なベストプラクティスのアドバイスを歓迎します。影響を最小限に抑えるために、このタスクを早い時間に実行するようにスケジュールすることを考えましたが、このタスクが完了するまでユーザーはアカウントへのアクセスを取り戻すことができないため、これは理想からはほど遠いものです。

追加情報:

  • SQL Server2008R2標準
  • すべてのテーブルにはクラスター化インデックスがあります
  • 関連するテーブルの削除コマンドにトリガーが関連付けられていません
  • 外部キー参照は多くのテーブルに存在しますが、削除順序がこれを説明しています。

編集:16:52 GMT

削除手順は約20のテーブルに影響します。最大のものは約500万件のレコードがあります。他には200,000がなく、1000〜2000のレコードしか含まれていないものもあります。

4

5 に答える 5

4

accountNumberすべてのテーブルにインデックスがありますか?

その列の句を使用して削除することを確認するWHEREと、これが役立つ場合があります。

別のオプション(そしておそらくさらに良い解決策)は、夜間に削除操作をスケジュールすることです。たとえば、ユーザーが自分のアカウントを削除することを選択した場合、フラグを設定するだけで、削除ジョブが夜間に実行され、削除のフラグが付けられたアカウントが実際に削除されます。

于 2013-02-27T14:29:29.567 に答える
1

accountNumberフィールドにインデックスがある場合、削除に時間がかかるのは、ロック(他のプロセスによって生成されたもの)またはそれぞれのテーブルの影響を受ける外部キーが原因だと思います。

  1. ロックが原因である場合は、実際にそれを実行できるnolockを使用してロックを減らすことができるかどうかを確認する必要があります。
  2. 外部キーの問題がある場合..まあ待つ必要があります..しかし待ちたくない場合で、アプリケーションロジックがFKの強制に依存していない場合(FK違反についてアプリケーションにエラーを送信したり、または、アプリケーションが完璧であると感じた後、短期間FKが不要になった場合は、ALTER TABLE xxx NOCHECK CONSTRAINT allを使用して、削除する前に関連するFKを無効にしてから、再度有効にすることができます。

もちろん、純粋主義者は後者のせいにするでしょうが、私は必要が生じたときにこれを何度も使用していました。

于 2013-02-27T14:34:38.347 に答える
0

SqlCommand.CommandTimeoutが短い答えです。その値を増やします。

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.commandtimeout.aspx

接続タイムアウトはCommandTimeoutと同じではないことに注意してください。

..。

各テーブルの「accountNumber」にインデックスがありますか?

テーブルのサロゲートキーにクラスター化されたキーを含めることはできますが、「accountNumber」を含めることはできません。

..。

基本的に、ここで実行プランを確認する(または実行プランを投稿する)必要があります。

しかし、ここにその列のインデックスを試すための「スターターコード」があります。

if exists (select * from dbo.sysindexes where name = N'IX_myDataTable1_accountNumber' and id = object_id(N'[dbo].[myDataTable1]'))
    DROP INDEX [dbo].[myDataTable1].[IX_myDataTable1_accountNumber]
GO

CREATE INDEX [IX_myDataTable1_accountNumber] ON [dbo].[myDataTable1]([accountNumber]) 
GO
于 2013-02-27T14:26:55.637 に答える
0

データベースをReadCommittedSnapshotモードに切り替える価値があるかもしれません。これはパフォーマンスに影響しますが、アプリケーションによって異なります。

コミットされたスナップショットの読み取りモードでは、ライターはライターをブロックしますが、ライターとリーダーは互いにブロックしなくなります。テーブル上のどのようなアクティビティが削除によって妨げられているかはわかりません。したがって、これが役立つかどうかを判断するのは少し難しいですか?

http://msdn.microsoft.com/en-us/library/ms188277(v=sql.105).aspx

そうは言っても、最大1万行のテーブルを削除するのに3〜5分かかると、とてつもなく遅いように思われます。外部キーについて言及しましたが、外部キーにはインデックスが付けられていますか?そうでない場合、削除すると、もう一方の端でテーブルスキャンが発生し、RIが破損していないことを確認できます。最初に確認してください。SQL Server Profilerは、これらの削除クエリの読み取り/書き込みについて何と言っていますか?

于 2013-02-27T15:01:18.827 に答える
0

あなたが試してみたいかもしれない1つの方法はこれです:

  1. SPを作成します。
  2. テーブルごとに、適切なサイズの小さなバッチの行を削除します(たとえば、バッチごとに10行)。
  3. 各バッチ削除をトランザクション内に配置し、各トランザクション間にカスタム遅延を追加します。

例:

    DECLARE @DeletedRowsCount INT = 1, @BatchSize INT = 300;
    WHILE (@DeletedRowsCount> 0) BEGIN
        BEGIN TRANSACTION  
            DELETE TOP (@BatchSize) dbo.Table
            FROM dbo.Table
            WHERE Id = @PortalId;
            SET @DeletedRowsCount = @@ROWCOUNT;
        COMMIT;

        WAITFOR DELAY '00:00:05';
    END

SPがなくても同じことができると思います。実際、それはそのように良いかもしれません。

于 2021-05-28T12:51:19.063 に答える