10

No sé si esto es un problema con la forma en que los estoy usando o la implementación de Microsoft, pero los parámetros de valor de tabla de SQL 2008 son extremadamente lentos.Problemas con el rendimiento de parámetro de valor de tabla

Generalmente, si necesito usar un TVP es porque tengo muchos registros, actualmente parecen ser inusualmente lentos para algo más que el menor número de registros.

los estoy llamando en .Net así:

// get the data 
DataTable data = GetData(); 

com.CommandText = "sprocName" 

// create the table-value parameter 
var tvp = com.Parameters.AddWithValue("data", data); 
tvp.SqlDbType = SqlDbType.Structured; 

com.ExecuteNonQuery(); 

me encontré perfilador para ver por qué, y la instrucción SQL real es algo como esto:

declare @data table ... 

insert into @data (... fields ...) values (... values ...) 
-- for each row 
insert into @data (... fields ...) values (... values ...) 

sprocName(@data) 

Esa es una muy lenta manera de hacerlo sin embargo. Sería mucho más rápido si lo hiciera en su lugar:

insert into @data (... fields ...) 
values (... values ...), 
     (... values ...), 
     -- for each row 
     (... values ...) 

No estoy seguro de por qué no está usando la sintaxis nueva, mucho más rápido. O incluso lo que sea que haga bajo el capó con SqlBulkCopy.

La nueva sintaxis se agregó en SQL 2008, pero también lo son los TVP (creo).

¿Hay alguna opción para hacerlo? O algo que me estoy perdiendo?

+3

Si trazas del Analizador de SQL están marcados como RPC (no lotes), significa que el texto que se muestra no es un texto real que se transmite de alambre , pero un texto reconstruido a partir de los parámetros reales de RPC. Eso no explica por qué es lento, pero puede no ser significativo. –

Respuesta

3

Vea la sección "Parámetros con valores de tabla frente a las operaciones masivas de inserción"
http://msdn.microsoft.com/en-us/library/bb510489.aspx

Cita: "... los parámetros con valores de tabla se desempeñan bien para la inserción de menos de 1000 filas."

También tiene una tabla para mostrar qué tecnología usar en función de la velocidad de las operaciones de inserción.

Espero que esto ayude, buena suerte.

+0

Saludos. Sin embargo, en la práctica, incluso para una tabla con unos cientos de filas, los TVP siguen siendo notablemente más lentos que la opción de lista de valores e incluso más lenta que 'SqlBulkCopy' después de la primera llamada (la primera vez que se ejecuta' SqlBulkCopy' toma 1 extra 2s por alguna razón). – Keith

+0

@Keith y Robert, la información en esa documentación vinculada debe tomarse en contexto. Por favor vea mi respuesta, y en particular el Libro Blanco al que he vinculado en la parte inferior. –

+1

@srutzky, gracias, eso es una gran respuesta. – Robert

9

Si los TVP son "notablemente más lentos" que las otras opciones, lo más probable es que no los implemente correctamente.

  1. No debe utilizar una DataTable, a menos que su aplicación tenga uso fuera de enviar los valores al TVP. El uso de la interfaz IEnumerable<SqlDataRecord> es más rápido y utiliza menos memoria ya que no está duplicando la colección en la memoria solo para enviarla a la base de datos. esto he documentado en los siguientes lugares:
  2. No debe usar AddWithValue para el parámetro SqlParameter, aunque esto probablemente no sea un problema de rendimiento. Pero aún así, debe ser:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured); 
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection); 
    
  3. TVP son variables de tabla y como tal no mantienen estadísticas. Es decir, informan que solo tienen 1 fila para Query Optimizer.Así que, en su proc, ya sea:
    • uso a nivel de declaración de recompilación en cualquier consulta utilizando el TVP para otra cosa que no sea un simple SELECT: OPTION (RECOMPILE)
    • Crear una tabla temporal local (es decir, solo #) y copiar el contenido de la TVP en la tabla temporal

en cuanto a por qué usted está viendo:

insert into @data (... fields ...) values (... values ...) 
-- for each row 
insert into @data (... fields ...) values (... values ...) 

en lugar de:

insert into @data (... fields ...) 
values (... values ...), 
     (... values ...), 

si eso es realmente lo que está sucediendo, entonces:

  • Si los insertos se están haciendo dentro de una transacción, entonces no hay diferencia de rendimiento real de
  • El valor más reciente -list sintaxis (es decir VALUES (row1), (row2), (row3)) se limita a algo así como 1000 filas y, por lo tanto, no es una opción viable para los TVP que no tienen ese límite.

Por favor, vea también el documento técnico del Equipo Asesor de Clientes de SQL Server: Maximizing Throughput with TVP

Cuestiones relacionadas