Pregunta

En mi solicitud utilizo TADOQuery con select (MSSQL) y vinculado con ella TClientDataSet. Tengo que insertar unos millones de discos y ApplyUpdates.

Así que lo que veo en el Analizador de SQL Server? Veo que para cada fila insertada tenemos 3 consultas: sp_prepare de secuencia de comandos de inserción, sp_execute con algunos valores y sp_unprepare

.

Quiero simplemente para preparar SQL una vez para todos los registros antes de inserción y unprepare después. ¿Cómo puedo hacerlo?

Alta después de

En la consulta Tengo un script para la ejecución del procedimiento almacenado:

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);

Se selecciona todos los campos de la tabla sTableName con algunos parámetros.

Ejemplo de inserción de perfilador:

paso 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

paso 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

paso 3:

exec sp_unprepare 486

y para todos de las nuevas filas.

¿Fue útil?

Solución 4

La respuesta estaba en el proveedor utilizado en TADOConnection. Cambiaron de MSDASQL a sqloledb y todo está bien ahora, sin ningún tipo de consultas adicionales.

Otros consejos

Debido a que está llamando a un procedimiento almacenado, y no una consulta en línea en su código, a continuación, SQL Server está tratando a cada llamada al procedimiento almacenado como una llamada independiente, y así se prepara y unpreparing cada vez. No estoy seguro de si hay una forma de evitar esto.

Si lo que está sucediendo dentro del procedimiento almacenado se puede hacer desde una consulta en su código, entonces se podría usar una estructura como esta que sólo prepararía la instrucción SQL primera vez:

{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;

Las disculpas si no he bastante de los nombres de propiedades y método correcto para el componente ADOQuery, no estoy en mi PC Delphi en el momento y que no suelen utilizar los componentes TADO, pero el concepto sigue siendo válida a partir este es un concepto TDataSet.

Pensamientos ...

  1. No es necesario preparar una llamada de procedimiento almacenado. En efecto, ya está preparado. Puede swicth si fuera poco en la mayoría de las implementaciones de los clientes.

  2. Es posible que no sea capaz de hacerlo por un millón de filas de una sola vez. Usted tiene un límite de tamaño de lote (por ejemplo, una sola llamada DB) de 256 MB (suponiendo predeterminado 4k paquetes de red).

  3. En otras implementaciones del cliente puede establecer un " tamaño de lote"(concepto diferente al punto 2), digamos 10.000, por lo que sólo serías 100 llamadas no un millón.

Creo que las otras respuestas pueden ser buenas para ayudar a optimizar el rendimiento, aunque supongo qué método se utiliza para acceder a la TClientDataSet realidad no importa, ya que en cualquier caso, la actualización de base de datos real es independiente (y genera automáticamente ).

Si la actualización funciona como una separada prepararse para cada línea, entonces parece que fue una mala elección de diseño por Borland, ya que es obvio que la actualización de muchas filas requerirá la misma consulta, sólo que con diferentes parámetros cada vez.

Por otro lado, TClientDataSet era para las bases de datos en memoria, lo que significa relativamente pequeñas bases de datos. El uso de algo así como un millón de filas, probablemente, va más allá del caso de uso pretendido.

Por otro lado, el canje de ClientDataSet desde su aplicación en este punto podría ser problemático. Yo diría que para la parte sensible rendimiento de la aplicación, me gustaría realizar un seguimiento de las filas modificadas a mí mismo y escribir una rutina de actualización manual utilizando las rutinas mencionadas anteriormente. Además de eso, usted podría tratar de modificar el código fuente del TClientDataSet para que sea más eficiente, o sub-clasificándola y reemplazando el método que aplica los cambios.

(En lo personal, yo uso SQLite3 para el almacenamiento en mis programas, por lo ClientDataSet es de poca utilidad y no he jugado mucho con él).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top