glitteringsound Ответов: 5

Как передать иерархию .NET collection of objects (parent-child) хранимой процедуре SQL server


Привет,

Мне нужно передать коллекцию .NET в хранимую процедуру. Моя коллекция содержит 1000 записей. Каждая запись содержит 2-3 дочерних объекта других типов.

Все, что мне нужно, чтобы вставить их сразу, вызвав хранимую процедуру из .NET.

Я уже пробовал TVP (табличный параметр), но это просто не удовлетворяет моим потребностям.

Для каждой записи корневого уровня мне нужно вызвать хранимую процедуру, передав корневую запись и соответствующие дочерние записи. Это делает весь процесс очень медленным.

Вот почему я ищу способ, чтобы я мог передать весь иерархический список сразу, а внутри хранимой процедуры, зацикливаясь и повторяя дочерние записи, я могу вставить родительские дочерние записи.

Как я могу этого достичь?


Что я уже пробовал:

Просто хранимая процедура, принимающая два TVP , один для родителя, а другой для связанных с ним детей

5 Ответов

Рейтинг:
2

#realJSOP

У меня никогда не было проблем с производительностью sql server, которые не были вызваны чем-то, что я сделал. Я не использую табличные параметры.

Вы можете либо повторить список и сохранить onbjects по одному за раз, либо сделать так, как предложил первый ответ, и сериализовать все данные в xml и передать XML в сохраненный proc. Я сам предпочитаю раздельные звонки, но это только я.


glitteringsound

Ранее я использовал entity framework для сохранения 100K rocords в базе данных, где каждый recod дополнительно содержит дочерние записи.

моя иерархия объектов такова :

открытый класс груза

{

....

List & lt;consignmentaddress> addresses {get; set;}

List & lt;consignmentline & gt; lines { get; set; }

}

Я мог бы ожидать, что количество партий = 100 тысяч, и каждая партия могла бы содержать 2 линии партий и в среднем 3 адреса партий.

Таким образом, все это составляет примерно = 100K + 200K + 300K = 600K записей .

Для вставки всех этих 600K записей я использовал entity framework, и это было чертовски медленно. Затем я разделил файл на куски и проанализировал 1000 записей и вставил их с помощью EF, каждый раз воссоздавая контекст. Это было очень хорошо . Но все же это не полностью удовлетворяет моему требованию ( так как в будущем я мог бы ожидать 500 тысяч записей корневого уровня, и каждая последующая запись могла бы содержать 3-4 дочерние записи в каждом списке. Это может сделать 1200K записей в базе данных).

Теперь мне нужно быстрое и эффективное решение.

Вот почему я хочу отправить всю иерархию сразу, чтобы я мог повторить эту коллекцию внутри SQL и вставить родительские дочерние записи. Поскольку это было бы близко к металлу, это было бы в 10 раз быстрее, чем entity framework.
Но в данный момент я повторяю этот список "консигнация" из .NET C# в цикле, и для каждой консигнации, наряду с ее дочерними элементами ( т. е. List<consignmentaddress>, List<consignmentline>), Я вызываю хранимую процедуру и отправляю эти 3 как TVP ( 1 для консигнации, 2-й для List<consignmentaddress>, 3-й для List<consignmentline>). Эта процедура также очень медленная. Потому что для 100K корневых записей происходит 100K вызовов хранимых процедур.

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

Рейтинг:
2

glitteringsound

Ранее я использовал entity framework для сохранения 100K rocords в базе данных, где каждый recod дополнительно содержит дочерние записи.

моя иерархия объектов такова :

открытый класс груза

{

....

List & lt;consignmentaddress> addresses {get; set;}

List & lt;consignmentline & gt; lines { get; set; }

}

Я мог бы ожидать, что количество партий = 100 тысяч, и каждая партия могла бы содержать 2 линии партий и в среднем 3 адреса партий.

Таким образом, все это составляет примерно = 100K + 200K + 300K = 600K записей .

Для вставки всех этих 600K записей я использовал entity framework, и это было чертовски медленно. Затем я разделил файл на куски и проанализировал 1000 записей и вставил их с помощью EF, каждый раз воссоздавая контекст. Это было очень хорошо . Но все же это не полностью удовлетворяет моему требованию ( так как в будущем я мог бы ожидать 500 тысяч записей корневого уровня, и каждая последующая запись могла бы содержать 3-4 дочерние записи в каждом списке. Это может сделать 1200K записей в базе данных).

Теперь мне нужно быстрое и эффективное решение.

Вот почему я хочу отправить всю иерархию сразу, чтобы я мог повторить эту коллекцию внутри SQL и вставить родительские дочерние записи. Поскольку это было бы близко к металлу, это было бы в 10 раз быстрее, чем entity framework.
Но в данный момент я повторяю этот список "консигнация" из .NET C# в цикле, и для каждой консигнации, наряду с ее дочерними элементами ( т. е. List<consignmentaddress>, List<consignmentline>), Я вызываю хранимую процедуру и отправляю эти 3 как TVP ( 1 для консигнации, 2-й для List<consignmentaddress>, 3-й для List<consignmentline>). Эта процедура также очень медленная. Потому что для 100K корневых записей происходит 100K вызовов хранимых процедур.

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


Рейтинг:
2

AFell2

Есть еще один вариант, который вы, возможно, захотите рассмотреть, а именно добавление и заполнение полей ссылочной целостности (Id, ParentId и т. д.) В вашем POCO (или новом POCO только для процесса вставки), а затем выполнение вставок на основе набора для каждого типа объекта. Можно использовать "метода SelectMany" синтаксис LINQ объединить несколько вложенных возвращает все наборы вместе.

Что замедляет процесс вставки в EF, так это то, что вы выполняете parent1-child1-child2, parent2-child3-child4 и т. д., А Sql Server не реагирует на оптимизацию вставок.

Если бы вы вставляли в операции на основе наборов, вы вставляли бы все родительские строки, затем все первые дочерние строки, а затем все вторые дочерние строки, сохраняя ссылочную целостность, в то время как SQL Server оптимизировал бы вставки.


glitteringsound

Кто бы SQL-сервер будет знать, что ребенок принадлежит к какой родитель?
и сколько детей существует для конкретного родителя в этом случае, если я сохраняю родителя и детей отдельно. Например, Консигнация 1 имеет 4 консигнационные линии, 3 консигнационных адреса, в то время как другая консигнация имеет 2 консигнационные линии и 5 консигнационных адресов

Рейтинг:
1

AFell2

Итак, вы говорите, что у вас есть структурированные данные, состоящие из родительских и дочерних записей, и хотя родительская схема статична, дочерние схемы имеют разные схемы.

Собираетесь ли вы измельчить данные и распределить их по нескольким таблицам базы данных с помощью одной хранимой процедуры? Единственный надежный способ сделать это в одной хранимой процедуре - сериализовать данные в XML или JSON (если вы работаете с Sql Server 2016) и заставить хранимую процедуру измельчить и загрузить данные в различные таблицы.


Рейтинг:
0

glitteringsound

Как sql server узнает, какой ребенок принадлежит какому родителю?