2

次の (サニタイズされた) コードでは、これらのエラーが発生することがあります。

テーブル 'database.dbo.Table' を削除できません。テーブルが存在しないか、権限がないためです。
データベースには、'Table' という名前のオブジェクトが既に存在します。

begin transaction  
    if exists (select 1 from database.Sys.Tables where name ='Table') 
        begin drop table database.dbo.Table end 

    Select top 3000 *
    into database.dbo.Table
    from OtherTable
commit

select * from database.dbo.Table

コードは同時に複数回実行できます。壊れる理由わかる人いますか?

4

3 に答える 3

7

なぜあなたが最初にこれをするのか聞いてもいいですか?一時テーブルの使用を検討するか、別の解決策を考え出す必要があります。

DDL ステートメントがトランザクションで DML ステートメントと同じように動作することには自信がありません。DDL 内で奇妙な動作をし、ストアド プロシージャを作成するブログ投稿を見たことがあります。

それとは別に、トランザクションの分離レベルを確認して、それを Serialized に設定することもできます。

編集

簡単なテストに基づいて、2 つの異なる接続で同じ SQL を実行しました。テーブルを作成したがトランザクションをコミットしなかった場合、2 番目のトランザクションがブロックされました。したがって、これは機能するはずです。このタイプの設計にはまだ注意が必要です。

于 2009-02-12T20:03:56.963 に答える
3

コードのどの部分で、このリソースへの複数アクセスを防止していますか?

begin transaction  
    if exists (select 1 from database.Sys.Tables where name ='Table') 
        begin drop table database.dbo.Table end 

    Select top 3000 *
    into database.dbo.Table
    from OtherTable
commit

トランザクションの開始はそれを行っていません。テーブルに追加された行に対するコミット/ロールバック シナリオの設定のみです。

(存在する場合はドロップ) は競合状態であり、(select..into) を使用してテーブルを再作成します。複数の人が一度にそのコードに飛び込むと、間違いなくあらゆる種類のエラーが発生します。他の人が破壊したばかりのテーブルを作成する人もいれば、もう存在しないテーブルを削除する人もいれば、挿入中のテーブルを削除する人もいます。うーん!

重要なリソースがビジー状態の場合は、他のユーザーの一時テーブルの提案を検討するか、アプリケーション ロックを使用して、他のユーザーがこのコードをまったく入力できないようにします。ドロップ/作成時のトランザクションは、あなたが望むものではありません。

于 2009-02-12T21:45:44.393 に答える
1

このプロセスでこのテーブルを使用しているだけの場合は、データの量に応じて、一時テーブルまたは ram テーブルを使用することをお勧めします。トランザクション コストを回避し、ディスク アクティビティを節約するために、RAM テーブルを頻繁に使用します。

于 2009-02-12T20:17:19.067 に答える