Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > MS SQL Server > Получение identity в batch insert-е


Автор: Любитель 18.9.2009, 22:07
Думаю, что понятней будет изложить проблему целиком (ну.. конечно, в максимально упрощённом виде).

Итак, есть:
1. Таблица иерарических данных с полями ID, ParentID и Name. Назовём её Options.
2. XML с иерархическими данными, скажем с тегами Item и именем в аттрибуте Name.
3. Надо данные из XML-а вставить в базу как можно эффективнее.

Был рассмотрен такой вариант (надеюсь не ошибся, ибо пишу из дома, по памяти), он работает, но ориентирован на GUID-овые айдишники:
Код

with OptionsCTE (Childs, ItemID, ParentID, Name) as
(
    select
        T.node.query('./*'),
        NEWID(),
        cast(null as uniqueidentifier),
        T.node.value('@Name', 'nvarchar(100)')
    from @xml.nodes('/Item') as T(node)
    union all
    select
        T.node.query('./*'),
        NEWID(),
        OptionsCTE.ItemID,
        T.node.value('@Name', 'nvarchar(100)')
    from OptionsCTE
    cross apply Childs.nodes('./Item') as T(node)
)
insert into Options (ID, ParentID, Name)
select ItemID, ParentID, Name from OptionsCTE


Вопрос - можно ли как-то заставить работать такой же запрос, но при использование identity-айдишников? В идеале нужна функция, которая позволяла бы получить следующее значение для внутреннего значения identity таблицы и меняла это значение. Разрешить явную вставку значения айдишника - уже не проблема, конечно.

Замечу, что просто базироваться на значении identity до вставок нельзя (и прибавлять к нему, условно говоря, номер элемента) - так как это нарушить возможность многопользовательской вставки.

Что посоветуете?

Автор: Akina 18.9.2009, 22:25
ммм... IDENT_CURRENT? Как я понимаю, тебе что новый identity, что последний+seed - пофиг, сложить-то сумеешь, а шаг получить несложно.

Добавлено через 4 минуты и 20 секунд
Правда, ориентироваться на вычисленное таким образом значение можно только если эта транзакция блокирует вставку в таблицу... 

Автор: Любитель 18.9.2009, 22:37
Цитата(Akina @  18.9.2009,  22:25 Найти цитируемый пост)
Правда, ориентироваться на вычисленное таким образом значение можно только если эта транзакция блокирует вставку в таблицу...  

Вот об том и речь:
Цитата(Любитель @  18.9.2009,  22:07 Найти цитируемый пост)
Замечу, что просто базироваться на значении identity до вставок нельзя (и прибавлять к нему, условно говоря, номер элемента) - так как это нарушить возможность многопользовательской вставки.


Лочить не хочется. Ведь при вставке самой идентити-значения генерятся с учётом возможности вставки из различных транзакций..
Блин, неужели в MS SQL нет возможности аналогичной нормальным сиквенсам? smile 

Автор: Zioma 18.9.2009, 23:10
Цитата(Любитель @ 18.9.2009,  20:37)
Блин, неужели в MS SQL нет возможности аналогичной нормальным сиквенсам? smile

Вы имеете ввиду Оракл?

Автор: Любитель 18.9.2009, 23:16
Ну.. из того, с чем работал - оракл, постгри. Вообще - я про концепцию (генерация уникальных значений инкриментом), а не конкретную реализацию. identity в MS SQL реализует эту концепцию, но.. либо неполно (с точки зрения "ручной" работы), либо я что-то не понимаю.

Автор: kobra 19.9.2009, 15:57
если я правилно понял задачу, тооптималнее будет вставить липовую запис, получить идентификатор, а потом модифицировать на нужный.
конечно можно разрешить вставку в поле идентити своего значения, но при многоползователском доступе, опасно

Автор: Любитель 19.9.2009, 16:08
Да, вообщем-то примерно так я вначале и сделал. Для конечного восстановления парент-айдишника были добавлены две колонки: номер и парент-номер в пределах одной кампании (одного XML-файла). А затем апдейтил ParentID по ним.

Но, как оказалось, для больших XML-ей (дело даже не в размере - порядка нескольких мегабайт, а во вложенности) производительность оставляла желать лучшего. Причём дело не в апдейте (там были созданы соответствующие индексы), основные затраты были на прасинг XML всё-таки.

Поэтому всё-таки, поменяли формат файла (к счастью, оказывается никого он не волновал), на линейный XML, в которым прописывались номера (подряд) и номера парентов при его экспорте в клиентском приложении. Сейчас в хранимку грузится линейный XML (с прописанной иерархией в виде отношений), затем апдейтятся реальные ParentID. Всё работает быстро, все довольны smile

Автор: Akina 19.9.2009, 16:17
Цитата(Любитель @  18.9.2009,  23:37 Найти цитируемый пост)
при вставке самой идентити-значения генерятся с учётом возможности вставки из различных транзакций

Не-а. Очередное значение генерится один раз, и непременно последовательное. Попробуй:
Открой транзакцию А, затем транзакцию Б, в Б сгенери identity, затем сделай её откат, затем сгенери identity в транзакции А. Как полагаешь, что получится в транзакции А?

Автор: Любитель 19.9.2009, 16:46
Мм.. Предполагаю, что на 2 больше, чем вначале. Сейчас проверю smile

Автор: Любитель 19.9.2009, 17:04
Ну.. Так и есть. Или я что-то не так понял?

Автор: Akina 19.9.2009, 18:30
Ну... и о каких там "учётах возможностей" может идти речь?
Очередной identiny или был сгенерён, или нет. Третьего не дано. Если мы получили очередное значение у СУБД - неважно, для использования или "на посмотреть" - всё, оно сгенерено, занято, больше не сгенерится.
А учитываться ничего не будет, оно никому не надо. Кто попросит, тот получит. А использовать или нет - это его дело.

Автор: Любитель 20.9.2009, 18:22
Да не - я не то имел ввиду. Я имел ввиду, что если взять текущее значение (IDENT_CURRENT) перед вставкой, а остальные рассчитать подряд - получится ерунда. А вот если бы была функция, которая инкрементила идентити и возвращала новое значение - то можно было бы решить начальную задачу (с включенным для нашей таблицы IDENTITY_INSERT).

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)