¿Puedo crear un tipo de tabla definido por el usuario y usarlo en la misma transacción?


13

Cuando ejecuto lo siguiente (en el estudio de administración, GO separará los comandos en lotes)

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

Recibo un mensaje de error de punto muerto. Mi proceso se ha estancado consigo mismo. He visto este comportamiento en 2008, 2008R2 y 2012.

¿Hay alguna forma de usar mi tipo recién creado dentro de la misma transacción que se creó?


¿Por qué haces esto dentro de una transacción? ¿Estás esperando un UDT 'temporal'?
Max Vernon

2
Sabía que obtendría esta pregunta. Es parte de una prueba de integración. El marco de prueba de integración realiza todo en una sola transacción.
Michael J Swart el

1
Una solución obvia sería crear los tipos necesarios para la prueba antes de ejecutarla. Sin embargo, eso no ayuda a automatizar las pruebas.
Max Vernon

@MichaelJSwart, ¿podrías explicar un poco más lo que estás tratando de lograr? Los tipos de tabla son tan restrictivos, que no puedo ver a dónde vas con esto.
Sebastian Meine

Respuestas:


15

Esto se ha informado no menos de cuatro veces. Este se cerró como se solucionó:

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

Pero eso no era cierto. (Consulte también la sección de soluciones alternativas; la solución alternativa que sugerí no siempre será aceptable).

Este se cerró como por diseño / no se solucionará:

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

Estos dos son más nuevos y aún activos :

http://connect.microsoft.com/SQLServer/feedback/details/800919/ (ahora cerrado como No soluciona )

http://connect.microsoft.com/SQLServer/feedback/details/804365/ (ahora cerrado como Por diseño )

Hasta que Microsoft pueda convencerse de lo contrario, tendrá que encontrar una solución alternativa: simplemente implemente todos los tipos antes de ejecutar su prueba, o divídalo en varias pruebas.

Intentaré obtener la confirmación de mis contactos sobre lo que Umachandar quiso decir con arreglado en el primer elemento, porque obviamente eso entra en conflicto con declaraciones posteriores.

ACTUALIZACIÓN # 1 (de, con suerte, exactamente 2)

El error original (que se cerró como solucionado) involucraba tipos de alias, pero no de tipo TABLE. Se informó sobre SQL Server 2005, que obviamente no tenía tipos de tabla y TVP. Parece que UC informó que el error con los tipos de alias que no son de tabla se corrigió en función de cómo manejan las transacciones internas, pero no cubrió un escenario similar que luego se introdujo con los tipos de tabla. Todavía estoy esperando la confirmación de si ese error original debería haberse cerrado alguna vez; He sugerido que los cuatro se cierren como por diseño. Esto se debe en parte a que es más o menos como esperaba que funcionara, y en parte porque UC me da la sensación de que "arreglarlo" para que funcione de una manera diferente es extremadamente complejo, podría romper la compatibilidad con versiones anteriores y sería útil en un Número muy limitado de casos de uso. Nada en contra de usted o su caso de uso, pero fuera de los escenarios de prueba I '

ACTUALIZACIÓN # 2

He blogueado sobre este tema:

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


1

Pude reproducir esto. El gráfico de punto muerto es bastante 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>

A mí me parece un error y le recomendaría que abra un elemento de conexión para ello.


Para solucionar su problema inmediato, puede usar tSQLt.NewConnection(supongo que está 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

Todavía no entiendo de dónde viene la necesidad de crear un tipo de tabla sobre la marcha y supongo que estás complicando demasiado tu prueba. Envíame un correo electrónico si quieres discutir.


2
Gracias por tu ayuda Sebastian. Desafortunadamente, no estoy usando tSQLt. No entiendes de dónde viene la necesidad de crear un tipo sobre la marcha porque no lo expliqué. No estoy complicando demasiado las cosas, pero no siento la necesidad de demostrarlo.
Michael J Swart

Bueno, mire el código fuente tSQLt de cómo se implementa tSQLt.NewConnection. Es bastante sencillo y también debería funcionar en su marco.
Sebastian Meine

1
Cualquier intento de crear el tipo y luego usarlo en la misma transacción da como resultado un punto muerto (vea mi informe de error, vinculado en la publicación de Aaron - último enlace); esta solución alternativa no funcionará (bueno, suponiendo que no haga algo tonto como confirmar una transacción abierta antes de ejecutar la declaración de entrada).
Jon Seigel

-1

A menos que alguien sepa diferente, no creo que haya una manera de hacer esto en una sola transacción. No creo que esto sea un error.

Primero, debe tomar un bloqueo de modificación de esquema (Sch-M) cuando crea el tipo. Como no confirma la transacción, el bloqueo permanece abierto. Luego intenta declarar una variable para ese tipo en la misma transacción. Esto intenta tomar un bloqueo de estabilidad de esquema (Sch-S). Esos dos tipos son incompatibles simultáneamente en el mismo objeto. Dado que están en la misma transacción, SQL lo trata como un punto muerto porque el Sch-S nunca se puede otorgar mientras la transacción está abierta.

Ejecute cada lote de uno en uno y seleccione contra sys.dm_tran_locks tan pronto como intente declarar la variable. Verá el mismo proceso sosteniendo un Sch-M y esperando un Sch-S en el mismo objeto.


3
Los tipos son incompatibles, pero pensé que el mismo proceso no tendría que esperar solo. Por ejemplo, puedo agregar una columna a una tabla y luego usarla en la misma transacción.
Michael J Swart el

3
El administrador de bloqueos debería descubrir que el proceso ya tiene un bloqueo (en realidad más fuerte) en el recurso y el proceso no debería tener que esperar. Después de todo, primero puede actualizar una fila y luego volver a leerla en la misma situación.
Sebastian Meine
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.