ユーザー定義のテーブルタイプを作成し、同じトランザクションで使用できますか?


13

次を実行すると(管理スタジオで、GOはコマンドをバッチに分割します)

use tempdb

begin tran
go

CREATE TYPE dbo.IntIntSet AS TABLE(
    Value0 Int NOT NULL,
    Value1 Int NOT NULL
)
go

declare @myPK dbo.IntIntSet;
go

rollback

デッドロックエラーメッセージが表示されます。私のプロセスはそれ自体でデッドロックしました。この動作は2008年、2008R2、2012年に見ました。

作成された同じトランザクション内で新しく作成されたタイプを使用する方法はありますか?


トランザクション内でこれを行うのはなぜですか?「一時的な」UDTを望んでいますか?
マックスヴァーノン

2
私はこの質問を受け取ることを知っていました。これは統合テストの一部です。統合テストフレームワークは、単一のトランザクションですべてを実行します。
マイケルJスワート

1
明らかな回避策は、テストを実行する前にテストに必要なタイプを作成することです。ただし、これはテストの自動化には役立ちません。
マックスヴァーノン

@MichaelJSwart、達成しようとしていることをもう少し詳しく説明していただけますか?テーブルの種類は非常に制限されているため、これを使用しているかどうかはわかりません。
セバスチャンマイネ

回答:


15

これは少なくとも4回報告されています。これは修正されたため閉じられました:

http://connect.microsoft.com/SQLServer/feedback/details/365876/

しかし、それは真実ではありませんでした。(回避策のセクションも見てください-私が提案した回避策は、必ずしも受け入れられるとは限りません。)

これは設計により閉鎖されました/修正されません:

http://connect.microsoft.com/SQLServer/feedback/details/581193/

これら2つはより新しく、まだアクティブです:

http://connect.microsoft.com/SQLServer/feedback/details/800919/(Wo n't Fixとして閉じられました)

http://connect.microsoft.com/SQLServer/feedback/details/804365/(By Designとして閉鎖されました

Microsoftが別の方法で納得できるまで、回避策を見つける必要があります。テストを実行する前にすべてのタイプを展開するか、複数のテストに分割します。

Umachandarが最初のアイテムで修正されたことの意味について、連絡先から確認を取得しようとします。これは明らかに後のステートメントと矛盾するためです。

更新#1(できれば、正確に2)

元のバグ(修正済みとしてクローズされた)にはエイリアスタイプが含まれていましたが、タイプではありませんでした TABLE。SQL Server 2005に対して報告されましたが、テーブルタイプとTVPは明らかにありませんでした。UCは、非テーブルエイリアスタイプのバグは内部トランザクションの処理方法に基づいて修正されたと報告したようですが、後でテーブルタイプで導入された同様のシナリオはカバーしませんでした。元のバグを修正済みとしてクローズすべきかどうかの確認をまだ待っています。設計上、4つすべてを閉じることを提案しました。これは、それが機能することを期待していたためであり、また別の方法で機能するように「修正」することは非常に複雑であり、後方互換性を壊し、非常に限られた数のユースケース。あなたやあなたのユースケースに反対することはありませんが、テストシナリオ以外では私は

更新#2

私はこの問題についてブログに書いています:

http://www.sqlperformance.com/2013/11/t-sql-queries/single-tx-deadlock


1

これを再現できました。デッドロックグラフは非常に興味深いものです。

<deadlock-list>
  <deadlock victim="process47f948">
    <process-list>
      <process id="process47f948" taskpriority="0" logused="0" waitresource="METADATA: database_id = 2 USER_TYPE(user_type_id = 257)" waittime="3607" ownerId="14873" transactionname="@myPK" lasttranstarted="2013-11-06T13:23:12.177" XDES="0x80f6d950" lockMode="Sch-S" schedulerid="1" kpid="2672" status="suspended" spid="54" sbid="0" ecid="0" priority="0" trancount="1" lastbatchstarted="2013-11-06T13:23:12.167" lastbatchcompleted="2013-11-06T13:23:12.163" clientapp="Microsoft SQL Server Management Studio - Query" hostname="xxxxx" hostpid="5276" loginname="xxxxx\xxxxx" isolationlevel="read committed (2)" xactid="14867" currentdb="2" lockTimeout="4294967295" clientoption1="671090784" clientoption2="390200">
        <executionStack>
          <frame procname="adhoc" line="2" sqlhandle="0x010002002d9fe3155066b380000000000000000000000000">
declare @myPK dbo.IntIntSet;     </frame>
        </executionStack>
        <inputbuf>

declare @myPK dbo.IntIntSet;
    </inputbuf>
      </process>
    </process-list>
    <resource-list>
      <metadatalock subresource="USER_TYPE" classid="user_type_id = 257" dbid="2" id="lock8009cc00" mode="Sch-M">
        <owner-list>
          <owner id="process47f948" mode="Sch-M" />
        </owner-list>
        <waiter-list>
          <waiter id="process47f948" mode="Sch-S" requestType="wait" />
        </waiter-list>
      </metadatalock>
    </resource-list>
  </deadlock>
</deadlock-list>

私にはバグのように見えるので、接続アイテムを開くことをお勧めします。


差し迫った問題を回避するために使用できますtSQLt.NewConnection(tSQLtを使用していると仮定します)

use tempdb

begin tran
go
EXEC tSQLt.NewConnection '
CREATE TYPE dbo.IntIntSet AS TABLE(
    Value0 Int NOT NULL,
    Value1 Int NOT NULL
)
';
go

declare @myPK dbo.IntIntSet;
go

rollback

テーブル型をその場で作成する必要性がどこから来ているのか、まだわかりません。テストが複雑になりすぎていると思います。議論したい場合は、私にメールを送ってください。


2
セバスチャンに助けてくれてありがとう。残念ながら、tSQLtは使用していません。私はそれを説明しなかったので、その場で型を作成する必要性がどこから来るのか理解できません。私は物事を複雑にしすぎていませんが、それを実証する必要性を感じていません。
マイケルJスワット

さて、tSQLt.NewConnectionの実装方法のtSQLtソースコードを見てください。それはかなり簡単であり、あなたのフレームワークでも動作するはずです。
セバスチャンマイネ

1
タイプを作成して同じトランザクションで使用しようとすると、デッドロックが発生します(アーロンの投稿-最後のリンクにリンクされているバグレポートを参照)。この回避策は機能しません(入力ステートメントを実行する前に開いているトランザクションをコミットするなどの愚かなことをしないと仮定して)。
ジョンセイゲル

-1

誰かが違うことを知っていない限り、単一のトランザクションでこれを行う方法はないと思います。これはバグだとは思わない。

最初に、型を作成するときにスキーマ変更ロック(Sch-M)を取得する必要があります。トランザクションをコミットしないため、ロックは開いたままになります。次に、同じトランザクションでその型に変数を宣言しようとします。これは、スキーマ安定性ロック(Sch-S)を取得しようとします。これら2つのタイプは、同じオブジェクトに対して同時に互換性がありません。それらは同じトランザクション内にあるため、トランザクションが開いている間はSch-Sを許可できないため、SQLはそれをデッドロックとして扱います。

各バッチを1つずつ実行し、変数を宣言しようとするとすぐにsys.dm_tran_locksに対して選択します。Sch-Mを保持し、同じオブジェクトでSch-Sを待機している同じプロセスが表示されます。


3
タイプには互換性がありませんが、同じプロセスがそれ自体を待つ必要はないと考えました。たとえば、テーブルに列を追加して、同じトランザクションで使用できます。
マイケルJスワット

3
ロックマネージャは、プロセスが既にリソースに対して(実際にはより強力な)ロックを保持していること、そしてプロセスが待機する必要がないことを把握する必要があります。結局、最初に行を更新してから、それを読み戻すこともできます-同じ状況です。
セバスチャンマイネ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.