Что польза альтернативна к увольнению хранимой процедуры 368 времена для обновления базы данных?

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

Для маленьких наборов данных это не проблема, но когда у меня был очень большой набор данных, которые потребовали, чтобы повторение 368 сохранило вызовы proc для обновления записей в базе данных, я понял, что у меня была проблема. Старший dev посмотрел на мой сохраненный код proc и сказал, что выглядел хорошо, но теперь я хотел бы исследовать лучший метод для отправки "пакетных" данных к базе данных.

Какие опции я имею для обновления базы данных в пакете? Действительно ли это возможно с сохраненным procs? Что другие опции я имею?

У меня не будет опции установки законченного ORM, но любой совет ценится.


Дополнительная вводная информация:

Наша текущая модель доступа к данным была создана 5 лет назад, и все вызовы к дб в настоящее время выполняются через модульные/статичные функции с именами как ExecQuery и GetDataTable. Я не уверен, что я обязан оставаться в рамках той модели, но я должен был бы обеспечить очень хорошее выравнивание для выхода наружу нашего текущего DAL для получения до DB.

Также стоящий замечания, я являюсь довольно новым когда дело доходит до операций CRUD и базы данных. Я очень предпочитаю играть/работать в стороне.NET кода, но данные должны храниться где-нибудь, правильно?


Сохраненное содержание Proc:

ALTER PROCEDURE [dbo].[spUpdateOrderDetailDiscountedItem] 
    -- Add the parameters for the stored procedure here
    @OrderDetailID decimal = 0,
    @Discount money = 0,
    @ExtPrice money = 0,
    @LineDiscountTypeID int = 0,
    @OrdersID decimal = 0,
    @QuantityDiscounted money = 0,
    @UpdateOrderHeader int = 0,
    @PromoCode varchar(6) = '',
    @TotalDiscount money = 0

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    Update OrderDetail
    Set Discount = @Discount, ExtPrice = @ExtPrice, LineDiscountTypeID = @LineDiscountTypeID, LineDiscountPercent = @QuantityDiscounted
    From OrderDetail with (nolock) 
    Where OrderDetailID = @OrderDetailID

    if @UpdateOrderHeader = -1
      Begin
        --This code should get code the last time this query is executed, but only then.
        exec spUpdateOrdersHeaderForSkuGroupSourceCode @OrdersID, 7, 0, @PromoCode, @TotalDiscount
      End
8
задан Ben McCormack 19 July 2010 в 15:27
поделиться

9 ответов

Простой и альтернативный способ, который я видел на практике, - это создание оператора SQL, состоящего из sql_execs, вызывающего sproc с параметрами в строке. Не уверен, рекомендуется это или нет, но с точки зрения .NET вы заполняете только одну команду SqlCommand и вызываете ExecuteNonQuery один раз ...

Обратите внимание, если вы выберете это, пожалуйста, используйте StringBuilder ! : -)

Обновление: Я предпочитаю ответ Криса Лайвли, до сих пор не знал о табличных параметрах ... к сожалению, OP использует 2005 год.

9
ответ дан 5 December 2019 в 05:44
поделиться

Если вы используете SQL 2008, вы можете использовать возвращающий табличное значение параметр , чтобы протолкнуть все обновления за один вызов s'proc.

обновление Между прочим, мы используем это в сочетании с оператором merge . Таким образом, sql server позаботится о том, чтобы определить, вставляем ли мы новые записи или обновляем существующие. Этот механизм используется в нескольких основных местах нашего веб-приложения и обрабатывает сотни изменений одновременно. Во время регулярной загрузки мы увидим, что этот процесс вызывается примерно 50 раз в секунду, и это НАМНОГО быстрее, чем любой другой способ, который мы нашли ... и, безусловно, НАМНОГО дешевле, чем покупка более крупных серверов БД.

16
ответ дан 5 December 2019 в 05:44
поделиться

Вы можете отправить полный набор данные как входные XML-данные для хранимой процедуры. Затем вы можете выполнить операции Set для изменения базы данных. На основе набора будет превосходить RBAR по производительности почти каждый раз.

3
ответ дан 5 December 2019 в 05:44
поделиться

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

В этом есть как хорошее, так и плохое.
Хорошо

  • Нет необходимости передавать данные по сети.
  • Быстрее, если ваша логика настроена на основе
  • Увеличивается

Плохо

  • Если у вас есть правила, запрещающие любую логику в базе данных, это нарушит ваш дизайн.
  • Если логика не может быть установлена ​​на основе, тогда вы можете столкнуться с другим набором проблем с производительностью.
  • Если у вас есть внешние зависимости, это может увеличить сложность.

Без подробной информации о том, какие именно операции вы выполняете с данными, трудно дать твердую рекомендацию.

ОБНОВЛЕНИЕ
Бен спросил, что я имел в виду в одном из моих комментариев о CLR и SQL Server. Прочтите Использование интеграции CLR в SQL Server 2005 . Основная идея состоит в том, что вы можете написать код .Net для манипулирования данными и сохранить этот код внутри самого SQL-сервера. Это избавляет вас от необходимости читать все данные в сети и таким образом отправлять обновления обратно.

Код вызывается вашими существующими процедурами и дает вам всю мощь .net, так что вам не нужно делать что-то вроде курсоров. Sql останется установленным, в то время как код .net может выполнять операции с отдельными записями.

Между прочим, именно так были реализованы такие вещи, как heirarchyid, в SQL 2008.

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

1
ответ дан 5 December 2019 в 05:44
поделиться

Можете ли вы создать пакетный оператор с 368 вызовами вашего proc, тогда по крайней мере у вас не будет 368 обходов. т.е. псевдокод

var lotsOfCommands = "spUpdateOrderDetailDiscountedItem 1; spUpdateOrderDetailDiscountedItem 2;spUpdateOrderDetailDiscountedItem ... 368'

var new sqlcommand(lotsOfCommands)
command.CommandType = CommandType.Text;

//execute command
0
ответ дан 5 December 2019 в 05:44
поделиться

У меня были проблемы при попытке сделать то же самое (через вставки, обновления и т. Д.). При использовании OleDbCommand с параметрами требовалось много времени, чтобы постоянно воссоздавать объект и параметры каждый раз, когда я его вызывал. Итак, я создал свойство для своего объекта для обработки такого вызова, а также добавил соответствующие «параметры» к функции. Затем, когда мне нужно было действительно вызвать / выполнить его, я перебирал каждый параметр в объекте, устанавливал его на то, что мне было нужно, а затем выполнял его. Это создало ЗНАЧИТЕЛЬНОЕ улучшение производительности ... Такой псевдокод моей операции:

protected OleDbCommand oSQLInsert = new OleDbCommand();
// the "?" are place-holders for parameters... can be named parameters, 
// just for visual purposes 
oSQLInsert.CommandText = "insert into MyTable ( fld1, fld2, fld3 ) values ( ?, ?, ? )";
// Now, add the parameters
OleDbParameter NewParm = new OleDbParameter("parmFld1", 0);
oSQLInsert.Parameters.Add( NewParm );

NewParm = new OleDbParameter("parmFld2", "something" );
oSQLInsert.Parameters.Add( NewParm );

NewParm = new OleDbParameter("parmFld3", 0);
oSQLInsert.Parameters.Add( NewParm );

Теперь команда SQL и заполнители для вызова готовы к работе ... Затем, когда я буду готов выполнить вызов это, я бы сделал что-то вроде ..

oSQLInsert.Parameters[0].Value = 123;
oSQLInsert.Parameters[1].Value = "New Value";
oSQLInsert.Parameters[2].Value = 3;

Тогда просто выполните это. Повторение сотен звонков может быть уничтожено временем, создавая ваши команды снова и снова ...

удачи.

0
ответ дан 5 December 2019 в 05:44
поделиться

Это одноразовое действие (например, «просто импортируйте эти 368 новых клиентов один раз») или вам необходимо регулярно выполнять 368 вызовов sproc?

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

IMO, преждевременная оптимизация вызовов базы данных для одноразовых действий не стоит того времени, которое вы тратите на нее.

0
ответ дан 5 December 2019 в 05:44
поделиться

Массовый импорт CSV

(1) Создайте вывод данных с помощью построителя строк как CSV, затем выполните массовый импорт CSV:

http://msdn.microsoft.com/en-us /library/ms188365.aspx

0
ответ дан 5 December 2019 в 05:44
поделиться

Параметры с табличными значениями были бы лучше, но поскольку вы работаете на SQL 05, вы можете использовать класс SqlBulkCopy для вставки партий записей. По моему опыту, это очень быстро.

0
ответ дан 5 December 2019 в 05:44
поделиться