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


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.