2009-11-06 2 views
3

В моем приложении я использую TADOQuery с select (MSSQL) и связанный с ним TClientDataSet. Мне нужно вставить около миллиона записей и ApplyUpdates.TClientDataSet и большая вставка

Итак, что я вижу в профилировщике SQL Server? Я вижу, что для каждая вставленная строка имеет 3 запроса: sp_prepare скрипта вставки, sp_execute его с некоторыми значениями и sp_unprepare.

Я хочу только подготовить sql один раз для всех записей, прежде чем вставлять и не готовить его после. Как мне это сделать?

Добавлено после:

В запросе У меня есть сценарий для хранимой процедуры:

tmpQuery := DefineQuery(FConnection, [ 
    'exec up_getOperatorDataSet ', 
    ' @tablename  = :tablename, ', 
    ' @operator  = :operator, ', 
    ' @forappend  = :forappend, ', 
    ' @withlinksonly = :withlinksonly, ', 
    ' @ids   = :ids ' 
], [ 
    Param(ftString, sTableName), 
    Param(ftInteger, FOperatorId), 
    Param(ftBoolean, opForAppendOnly in OpenParams), 
    Param(ftBoolean, opOnlyWithModelLinks in OpenParams), 
    Param(ftString, sIds) 
], Result); 

Он выбирает все поля из таблицы sTableName с некоторыми параметрами.

Пример вставки из профилировщика:

шаг 1:

declare @p1 int 
set @p1=486 
exec sp_prepare @p1 output,N'@P1 int,@P2 int,@P3 datetime,@P4 int,@P5 int,@P6 int,@P7 int,@P8 int,@P9 varchar(128),@P10 bit,@P11 numeric(19,4),@P12 smallint,@P13 smallint,@P14 smallint,@P15 smallint',N'insert into parser_prices 
    (operator_id, request_id, date, nights, model_hotel_id, model_meal_id, model_room_id, model_htplace_id, spo, hotelstop, price, frout_econom, frout_business, frback_econom, frback_business) 
values 
    (@P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8, @P9, @P10, @P11, @P12, @P13, @P14, @P15) 
',1 
select @p1 

шаг 2:

exec sp_execute 486,21,2000450,'2009-12-04 00:00:00',14,2118,22,-9555,18,'2009-10.MSK.Bali.13.10.09-27.03.10',0,15530.0000,3,3,3,3 

шаг 3:

exec sp_unprepare 486 

и это для всех новых строк.

+2

Можем ли мы увидеть пример сценария? Вы должны иметь возможность параметризовать его, и в этом случае вы можете предварительно настроить его, а затем просто изменять параметры каждый раз перед повторным выполнением. –

+0

Некоторые детали добавлены. – silent

ответ

0

Ответ был у поставщика, используемого в TADOConnection. Переключен с MSDASQL на SQLOLEDB, и все это прямо сейчас, без каких-либо дополнительных запросов.

+0

Водитель был причиной? Довольно странно .. –

1

Поскольку вы вызываете хранимую процедуру, а не встроенный запрос в свой код, тогда SQL Server обрабатывает каждый вызов хранимого процесса как отдельный вызов, и поэтому он готовит его и не разглашает его каждый раз. Я не уверен, есть ли способ обойти это.

Если все, что происходит внутри хранимая процедура может быть сделано из запроса в коде, то вы могли бы использовать структуру, как это, что бы только подготовить инструкцию SQL в первый раз:

{Prepare the insert query} 
ADOQuery1.SQL.Append('INSERT INTO Tablename'); 
ADOQuery1.SQL.Append('(StringField1, IntField2)');    {repeat as necessary} 
ADOQuery1.SQL.Append('VALUES (:sFieldValue1, :sFieldValue2)'); {repeat as necessary} 
ADOQuery1.SQL.Prepare; 

{In a For, While, Repeat loop, use:} 
ADOQuery1.ParamByName('sFieldValue1').AsString := 'Value for field 1'; 
ADOQuery1.ParamByName('sFieldValue2').AsInteger := 2; 
ADOQuery1.ExecSQL; 

Извинения, если Я не получил имена свойств и методов для компонента ADOQuery, на данный момент я не на моем ПК Delphi, и я обычно не использую компоненты TADO, но концепция по-прежнему применяется, поскольку это концепция TDataSet ,

+0

Да, это то, что мне нужно, но ... автоматически :) – silent

+0

Что значит автоматически? Вы имеете в виду, что это должно быть в триггере базы данных? –

+0

Автоматически означает, что я хочу, чтобы компоненты создавали правильный запрос без дополнительных объектов, которые я должен создать. – silent

0

Мысли ...

  1. Вам не нужно подготовить хранимую процедуру вызова. По сути, он уже подготовлен. Вы можете замаскировать его в большинстве клиентских реализаций.

  2. Возможно, вы не сможете сделать это за миллион строк за один раз. У вас есть batch size limit (eg a single DB call) of 256 MB (при условии, что сетевые пакеты по умолчанию 4k).

  3. В других реализациях клиента вы можете установить «batch size» (другая концепция в пункт 2), скажем, 10 000, поэтому вы будете делать только 100 звонков не один миллион.

+0

1. Я не готовлю свой выбор 2. Я знаю 3. И что? :) – silent

+0

@silent: 1. Вы готовитесь, потому что профайлер SQL показывает это: он может быть автоматическим, но может быть отключен обычно. 3. Можете ли вы пакетные звонки. В конце концов, это точка вашего вопроса, конечно. – gbn

+0

Вставка SQL генерирует TSQLResolver в Провайдере, а не я. Я отлаживаю его и обнаружил, что перед выполнением через TADOCommand у него нет готового флага. – silent

0

Я думаю, что другие ответы могут быть хорошо помогает настраивать производительность, хотя я предполагаю, какой метод вы используете для доступа к TClientDataSet действительно не имеет значения, так как в любом случае, фактическое обновление базы данных отдельно (и автоматически генерируется).

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

С другой стороны, TClientDataSet предназначался для баз данных в памяти, что означает относительно небольшие базы данных. Использование чего-то вроде миллиона строк, вероятно, выходит за рамки предполагаемого варианта использования.

С другой стороны, замена ClientDataSet из вашего приложения на данном этапе может быть проблематичной. Я бы сказал, что для чувствительной к производительности части вашего приложения я сам отслеживал измененные строки и записывал ручную процедуру обновления, используя описанные выше процедуры. Кроме того, вы можете попробовать изменить исходный код TClientDataSet, чтобы сделать его более эффективным или подклассифицировать его и переопределить метод, который применяет изменения.

(Лично я использую SQLite3 для хранения в своих программах, поэтому ClientDataSet мало полезен, и я не играл с ним много).

Смежные вопросы