Чи можу я створити визначений користувачем тип таблиці та використовувати його в одній транзакції?


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 роках.

Чи існує спосіб використання мого новоствореного типу всередині тієї самої транзакції, яку він створив?


Чому ви робите це всередині транзакції? Ви сподіваєтесь на "тимчасовий" УДТ?
— Макс Вернон

2
Я знав, що отримаю це питання. Це частина тесту на інтеграцію. Рамка тесту на інтеграцію виконує все в одній транзакції.
— Michael J Swart

1
Очевидною проблемою було б створення типів, необхідних для тесту до виконання тесту. Зрозуміло, що це не допоможе вам автоматизувати тестування.
— Макс Вернон

@MichaelJSwart, ви могли б трохи детальніше розібратися, чого ви намагаєтесь досягти? Типи таблиць настільки обмежуючі, що я не можу точно зрозуміти, чи ти збираєшся з цим.
— Себастьян Мейн

Відповіді:


15

Про це повідомлялося не менше чотирьох разів. Це було закрито як виправлено:

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

Але це було неправдою. (Також дивіться розділ обхідних шляхів - рішення, яке я запропонував, не завжди буде прийнятним.)

Це було закрито, як дизайн / не виправить:

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

Ці два новіші та активні :

http://connect.microsoft.com/SQLServer/feedback/details/800919/ (зараз закрито, як не виправлено )

http://connect.microsoft.com/SQLServer/feedback/details/804365/ (зараз закрито як за проектом )

Поки Microsoft не зможе переконатися в іншому, вам доведеться знайти вирішення - просто розгорніть всі типи перед запуском тесту або розбийте його на кілька тестів.

Я спробую отримати підтвердження від своїх контактів про те, що мав на увазі Умачандар під фіксованим у найдавнішому пункті, оскільки, очевидно, це суперечить пізнішим твердженням.

ОНОВЛЕННЯ №1 (приблизно, сподіваємось, саме 2)

Початкова помилка (яка була закрита як виправлена) стосувалася псевдонімів, але не типу TABLE. Про це повідомлялося проти SQL Server 2005, який, очевидно, не мав типів таблиць і TVP. Здається, UC повідомляв, що помилка з типами псевдонімів, які не є таблицею, була виправлена ​​на основі того, як вони обробляють внутрішні транзакції, але він не охоплював аналогічний сценарій, представлений згодом із типами таблиць. Я все ще чекаю на підтвердження того, чи повинна ця оригінальна помилка колись була закрита як виправлена; Я запропонував усіх чотирьох закрити, як за проектом. Почасти це тому, що я певним чином, як я очікував, що це буде працювати, а почасти тому, що я отримую від UC сенс, що "фіксація" його роботи по-іншому надзвичайно складна, може порушити сумісність і була б корисною для дуже обмежена кількість випадків використання. Нічого проти вас або вашої справи використання, але поза тестовими сценаріями я '

ОНОВЛЕННЯ №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. Ви не розумієте, звідки виникає потреба створити тип на льоту, тому що я не пояснив цього. Я не надто ускладнюю речі, але не відчуваю потреби демонструвати це.
— Michael J Swart

Ну, подивіться на вихідний код tSQLt, як реалізується tSQLt.NewConnection. Це досить прямо, і він повинен працювати і у ваших рамках.
— Себастьян Мейн

1
Будь-яка спроба створити тип і потім використовувати його в одній транзакції призводить до тупикової ситуації (див. Мій звіт про помилку, пов’язаний у публікації Аарона - остання посилання); це вирішення не буде працювати (добре, якщо припустити, що він не робить щось глухо, як зробити відкриту транзакцію перед виконанням вхідного оператора).
— Джон Сейгель

-1

Якщо хтось не знає іншого, я не думаю, що існує спосіб зробити це однією транзакцією. Я не думаю, що це помилка.

Спочатку потрібно створити замок модифікації схеми (Sch-M) під час створення типу. Оскільки ви не здійснюєте транзакцію, блокування залишається відкритим. Потім ви намагаєтеся оголосити змінну цього типу в одній транзакції. Це намагається зняти схему стабільності схеми (Sch-S). Ці два типи несумісні одночасно на одному об'єкті. Оскільки вони знаходяться в одній транзакції, SQL розглядає це як тупик, оскільки Sch-S ніколи не може бути наданий, поки транзакція відкрита.

Запустіть кожну партію по черзі та виберіть проти sys.dm_tran_locks, як тільки ви спробуєте оголосити змінну. Ви побачите той самий процес, що тримає Sch-M і чекає Sch-S на тому ж об'єкті.


3
Типи несумісні, але я вважав, що той самий процес не повинен буде чекати на себе. Наприклад, я можу додати стовпчик до таблиці, а потім використовувати його в тій же транзакції.
— Michael J Swart

3
Менеджер блокування повинен зрозуміти, що процес вже містить (фактично сильніший) замок на ресурсі, і процес не повинен чекати. Зрештою, ви можете спочатку оновити рядок, а потім прочитати його ще в такій же ситуації.
— Себастьян Мейн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.