最近、100,000レコードに対して更新クエリを実行しました。クエリの実行中にミスを犯し、ネットワークケーブルをすぐに抜いたことに気付きました。
更新クエリ
- 処理を停止して完全にロールバックしますか?
- 処理を完了してコミットしますか?
- 処理を停止し、ターゲット行の一部のみを更新したままにしますか?
最近、100,000レコードに対して更新クエリを実行しました。クエリの実行中にミスを犯し、ネットワークケーブルをすぐに抜いたことに気付きました。
更新クエリ
回答:
NickとMartinが述べたように、クエリの最終的なステータスは、クエリが完了する前にSQL Serverがネットワークケーブルのプルについて知っているかどうかによって異なります。以下からのオンラインブック(私はそれがこのために同等のトピックがであることは興味深い見つけるのに2000、2005、2008、および2008 R2ではなく、2012または2014):
エラーが原因でトランザクションを正常に完了できない場合、SQL Serverはトランザクションを自動的にロールバックし、トランザクションによって保持されているすべてのリソースを解放します。データベースエンジンのインスタンスへのクライアントのネットワーク接続が切断された場合、ネットワークが切断のインスタンスを通知すると、接続の未処理のトランザクションはすべてロールバックされます。クライアントアプリケーションに障害が発生した場合、またはクライアントコンピューターがダウンまたは再起動した場合も、これにより接続が切断され、ネットワークから切断が通知されると、データベースエンジンのインスタンスが未処理の接続をロールバックします。クライアントがアプリケーションからログオフすると、未処理のトランザクションはすべてロールバックされます。
(余談ですが、最後の2番目の文の接続というのは、おそらくトランザクションを意味していました。接続をどのようにロールバックするかはわかりません。)
同様に、SQL Serverは、サーバーが予期せずシャットダウンされた後、回復中にトランザクションを元に戻したりやり直したりすることがあります。これは、シャットダウン時のトランザクションの状態に依存します。私は人々があなたがやろうとしていたことを達成するためにこの戦術を使用することを見てきました(トランザクションをキャンセルします)、サーバーが再び起動したとき、作業の多くは単純にやり直されました予想よりもゼロまで)。
そのため、ネットワークケーブルを引っ張ったり、マシンの電源を切ったりするなど、パニックで抜本的なことをする代わりに、重要なシステムに対してアドホッククエリを実行することについて、より良い規律を持つことをお勧めします。たとえば、次の代わりに:
UPDATE dbo.sometable
-- where *oops* I forgot this part
これを持っています:
BEGIN TRANSACTION;
UPDATE dbo.sometable
-- where *oops* I forgot this part
-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;
その後、更新が実際に正しい場合は、COMMIT
パーツを強調表示して実行できます。そうでない場合は、落ち着いてROLLBACK
パーツを強調表示して実行できます。SSMS Tools Packなどのアドインを使用してNew Query
テンプレートを編集し、その定型文を含めることもできます。
トランザクションが他のユーザーをブロックしているため、クエリを実行してからコミットまたはロールバックしない場合でも、問題が発生する可能性があります。しかし、これは取り返しのつかないほどデータを変更するよりはましです。
そしてもちろん、いつものように、信頼できるバックアップを用意してください。
@Aaronは正しいです。コマンドの前にトランザクションを作成するのが最善の策です。それをするのを忘れることができないなら、1つのオプションはTools-Options
設定に入って、つけることSET IMPLICIT_TRANSACTIONS
です。これにより、特定のコマンドが実行されるとすぐにトランザクションが自動的に開始されます。これにUPDATE
はDELETE
などが含まれます。これは、何らかのコマンドのかなり完全なリストのよう"change"
です。 SELECT
リストにも含まれておりwill
、トランザクションを開始します。トランザクションを開始するコマンドの完全なリストは、この設定で確認できます。トランザクションが既に開始されている場合、トランザクションは作成されません。これのマイナス面は、COMMIT
変更を行った後に覚えておく必要があることです。
注:@Aaronの提案に基づいて、これを再度強調します。
This is very important! You will have to remember to COMMIT after any change made!
基本的にはBEGIN
、トランザクションを忘れて、何かをめちゃくちゃにしてしまいます。COMMIT
トランザクションを忘れて、それを開いたままにして、その日のままにしておくとハングします。トランザクションをロールバックすると考えてクエリウィンドウを閉じただけでテストしましたが、トランザクションをコミットまたはロールバックするかどうかを確認しました。
SELECT
を開始します(投稿したリンクにも記載されています)
私は本当に依存すると思います:
ネットワークケーブルを抜く前にコマンドが既にサーバーに到達している場合、コマンドは引き続き正常に実行されます。
すべての更新コマンドをカプセル化するためのTransactionScope(他の言語ではない.Netで使用)がある場合、transactionScope.Complete()が実行されていないが保証されていない場合にのみ、トランザクションのコミットを停止できます。 。