Posso creare un tipo di tabella definito dall'utente e utilizzarlo nella stessa transazione?


13

Quando eseguo quanto segue (in Management Studio, GO separerà i comandi in batch)

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

Viene visualizzato un messaggio di errore di deadlock. Il mio processo si è bloccato con se stesso. Ho visto questo comportamento nel 2008, 2008R2 e 2012.

C'è un modo per usare il mio tipo appena creato all'interno della stessa transazione che è stata creata?


Perché lo stai facendo all'interno di una transazione? Stai sperando in un UDT 'temporaneo'?
Max Vernon,

2
Sapevo che avrei avuto questa domanda. Fa parte di un test di integrazione. Il framework di test di integrazione esegue tutto in un'unica transazione.
Michael J Swart,

1
Una soluzione ovvia sarebbe quella di creare i tipi necessari per il test prima di eseguire il test. Chiaramente, ciò non ti aiuta ad automatizzare i test, tuttavia.
Max Vernon,

@MichaelJSwart, potresti approfondire un po 'di più, cosa stai cercando di ottenere? I tipi di tabella sono così restrittivi, che non riesco proprio a capire se stai andando con questo.
Sebastian Meine,

1
Cordiali saluti, ho scritto un
Aaron Bertrand

Risposte:


15

Questo è stato segnalato non meno di quattro volte. Questo è stato chiuso come risolto:

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

Ma questo non era vero. (Guarda anche la sezione delle soluzioni alternative - la soluzione che ho suggerito non sarà sempre accettabile.)

Questo è stato chiuso come da progetto / non risolto:

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

Questi due sono più recenti e ancora attivi :

http://connect.microsoft.com/SQLServer/feedback/details/800919/ (ora chiuso come non risolto )

http://connect.microsoft.com/SQLServer/feedback/details/804365/ (ora chiuso come da progetto )

Fino a quando Microsoft non può essere convinta diversamente, dovrai trovare una soluzione alternativa: devi solo distribuire tutti i tipi prima di eseguire il test o suddividerlo in più test.

Cercherò di ottenere conferma dai miei contatti su ciò che Umachandar intendeva per risolto nel primo articolo, perché ovviamente è in conflitto con dichiarazioni successive.

AGGIORNAMENTO # 1 (di, si spera, esattamente 2)

Il bug originale (che era stato chiuso come riparato) riguardava tipi di alias, ma non di tipo TABLE. È stato segnalato contro SQL Server 2005, che ovviamente non aveva tipi di tabella e TVP. Sembra che UC abbia riferito che il bug con tipi di alias non di tabella è stato corretto in base al modo in cui gestiscono le transazioni interne, ma non copriva uno scenario simile successivamente introdotto con i tipi di tabella. Sto ancora aspettando la conferma se quel bug originale avrebbe dovuto essere chiuso come riparato; Ho suggerito di chiudere tutti e quattro come da progetto. Questo in parte perché è un po 'come mi aspettavo che funzionasse, e in parte perché ho capito da UC che "ripararlo" in modo diverso è estremamente complesso, potrebbe rompere la compatibilità con le versioni precedenti e sarebbe utile in un numero molto limitato di casi d'uso. Nulla contro di te o il tuo caso d'uso, ma al di fuori degli scenari di test

AGGIORNAMENTO # 2

Ho scritto un blog su questo problema:

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


1

Sono stato in grado di riprodurre questo. Il grafico del deadlock è piuttosto curioso:

<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>

Mi sembra un bug e ti consiglio di aprire un elemento di connessione per questo.


Per aggirare il tuo problema immediato puoi usare tSQLt.NewConnection(suppongo tu stia usando 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

Continuo a non capire da dove provenga la necessità di creare un tipo di tabella al volo e presumo che tu stia complicando troppo il tuo test. Inviami una email se vuoi discutere.


2
Grazie per il tuo aiuto Sebastian. Sfortunatamente, non sto usando tSQLt. Non capisci da dove provenga la necessità di creare un tipo al volo perché non l'ho spiegato. Non sto complicando troppo le cose, ma non sento il bisogno di dimostrarlo.
Michael J Swart,

Bene, guarda il codice sorgente di tSQLt su come viene implementato tSQLt.NewConnection. È abbastanza semplice e dovrebbe funzionare anche nel tuo framework.
Sebastian Meine,

1
Qualsiasi tentativo di creare il tipo e quindi utilizzarlo nelle stesse transazioni si traduce in deadlock (vedere la mia segnalazione di bug, collegata nel post di Aaron - ultimo link); questa soluzione alternativa non funzionerà (beh, supponendo che non faccia qualcosa di stupido come eseguire una transazione aperta prima di eseguire l'istruzione input).
Jon Seigel,

-1

A meno che qualcuno non sappia diversamente, non credo che ci sia un modo per farlo in una singola transazione. Non penso che questo sia un bug.

Innanzitutto, devi creare un blocco di modifica dello schema (Sch-M) quando crei il tipo. Poiché non esegui il commit della transazione, il blocco rimane aperto. Quindi si tenta di dichiarare una variabile per quel tipo nella stessa transazione. Questo tenta di ottenere un blocco di stabilità dello schema (Sch-S). Questi due tipi sono contemporaneamente incompatibili sullo stesso oggetto. Dal momento che sono nella stessa transazione, SQL lo considera un deadlock perché Sch-S non può mai essere concesso mentre la transazione è aperta.

Eseguire ogni batch uno alla volta e selezionare contro sys.dm_tran_locks non appena si tenta di dichiarare la variabile. Vedrai lo stesso processo tenendo uno Sch-M e aspettando uno Sch-S sullo stesso oggetto.


3
I tipi sono incompatibili, ma ho pensato che lo stesso processo non avrebbe dovuto attendere su se stesso. Ad esempio, posso aggiungere una colonna a una tabella e quindi utilizzarla nella stessa transazione.
Michael J Swart,

3
Il gestore dei blocchi dovrebbe capire che il processo ha già un blocco (effettivamente più forte) sulla risorsa e che il processo non dovrebbe attendere. Dopo tutto, puoi prima aggiornare una riga e poi rileggerla anche nella stessa situazione.
Sebastian Meine,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.