Tengo un proceso que toma un montón de registros (1000) y los opera, y cuando termine, necesito marcar una gran cantidad de ellos como procesados. Puedo indicar esto con una gran lista de ID. Estoy tratando de evitar el patrón de "actualizaciones en un bucle", así que me gustaría encontrar una forma más eficiente de enviar esta bolsa de ID a un proceso almacenado de MS SQL Server 2008.
Propuesta n. ° 1: Parámetros de valores de tabla. Puedo definir un tipo de tabla con solo un campo de ID y enviar una tabla llena de ID para actualizar.
Propuesta n. ° 2: parámetro XML (varchar) con OPENXML () en el cuerpo del proceso.
Propuesta n. ° 3: análisis de la lista. Prefiero evitar esto, si es posible, ya que parece difícil de manejar y propenso a errores.
¿Alguna preferencia entre estas o alguna idea que me haya perdido?
fuente
Respuestas:
Los mejores artículos sobre este tema son de Erland Sommarskog:
Cubre todas las opciones y explica bastante bien.
Perdón por la brevedad de la respuesta, pero el artículo de Erland sobre matrices es como los libros de Joe Celko sobre árboles y otras delicias de SQL :)
fuente
Hay una gran discusión sobre esto en StackOverflow que cubre muchos enfoques. El que prefiero para SQL Server 2008+ es usar parámetros con valores de tabla . Esta es esencialmente la solución de SQL Server para su problema: pasar una lista de valores a un procedimiento almacenado.
Las ventajas de este enfoque son:
Sin embargo, tome nota: si llama a un procedimiento almacenado que usa TVP a través de ADO.NET u ODBC y observa la actividad con SQL Server Profiler, notará que SQL Server recibe varias
INSERT
instrucciones para cargar el TVP, una para cada fila en el TVP , seguido de la llamada al procedimiento. Esto es por diseño . Este lote deINSERT
s debe compilarse cada vez que se llama al procedimiento, y constituye una pequeña sobrecarga. Sin embargo, incluso con esta sobrecarga, los TVP aún eliminan otros enfoques en términos de rendimiento y usabilidad para la mayoría de los casos de uso.Si desea obtener más información, Erland Sommarskog tiene toda la información sobre cómo funcionan los parámetros con valores de tabla y ofrece varios ejemplos.
Aquí hay otro ejemplo que inventé:
fuente
CREATE TYPE
declaración al principio se ejecutó correctamente? ¿Qué versión de SQL Server está ejecutando?@customer_list
no es@param1
. El ejemplo simplemente demuestra que puede mezclar diferentes tipos de parámetros.Todo el tema se discute en el artículo definitivo de Erland Sommarskog: "Matrices y listas en SQL Server" . Elija cuál versión elegir.
Resumen, para pre SQL Server 2008 donde los TVP triunfan sobre el resto
Vale la pena leer el artículo de todos modos para ver otras técnicas y pensamientos.
Editar: respuesta tardía para grandes listas en otros lugares: pasar parámetros de matriz a un procedimiento almacenado
fuente
Sé que llego tarde a esta fiesta, pero tuve un problema en el pasado, tuve que enviar hasta 100K números bigint e hice algunos puntos de referencia. Terminamos enviándolos en formato binario, como una imagen, que fue más rápido que todo lo demás para números de hasta 100K.
Aquí está mi viejo código (SQL Server 2005):
El siguiente código está empacando enteros en un blob binario. Estoy invirtiendo el orden de bytes aquí:
fuente
Estoy dividido entre remitirlo a SO o responderlo aquí, porque esta es casi una pregunta de programación. Pero como ya tengo una solución que uso ... la publicaré;)
La forma en que funciona es alimentar una cadena delimitada por comas (división simple, no hace divisiones de estilo CSV) en el procedimiento almacenado como varchar (4000) y luego alimentar esa lista en esta función y obtener una tabla práctica de nuevo, una tabla de solo varchars.
Esto le permite enviar los valores de solo los identificadores que desea procesar, y puede hacer una unión simple en ese punto.
Alternativamente, podría hacer algo con un CLR DataTable y alimentarlo, pero eso es un poco más costoso de soportar y todos entienden las listas CSV.
fuente
Regularmente recibo conjuntos de miles de filas y 10000 de filas enviadas desde nuestra aplicación para ser procesadas por varios procedimientos almacenados de SQL Server.
Para satisfacer las demandas de rendimiento, utilizamos TVP, pero debe implementar su propio resumen de dbDataReader para superar algunos problemas de rendimiento en su modo de procesamiento predeterminado. No entraré en los cómo y los porqués, ya que están fuera del alcance de esta solicitud.
No consideré el procesamiento de XML, ya que no he encontrado una implementación de XML que siga funcionando con más de 10,000 "filas".
El procesamiento de la lista se puede manejar mediante el procesamiento de tablas de conteo (números) de una y dos dimensiones. Los hemos usado con éxito en varias áreas, pero los TVP bien administrados son más eficaces cuando hay más de un par de cientos de "filas".
Al igual que con todas las opciones relacionadas con el procesamiento de SQL Server, debe realizar su selección según el modelo de uso.
fuente
Finalmente tuve la oportunidad de hacer algunos TableValuedParameters y funcionan muy bien, así que voy a pegar un código de lotta completo que muestre cómo los estoy usando, con una muestra de algunos de mis códigos actuales: (nota: usamos ADO .RED)
También tenga en cuenta: estoy escribiendo un código para un servicio, y tengo muchos bits de código predefinidos en la otra clase, pero estoy escribiendo esto como una aplicación de consola para poder depurarlo, así que eliminé todo esto de La aplicación de consola. Disculpe mi estilo de codificación (como cadenas de conexión codificadas) ya que era como "construir uno para tirar". Quería mostrar cómo uso a
List<customObject>
e insertarlo en la base de datos fácilmente como una tabla, que puedo usar en el procedimiento almacenado. C # y el código TSQL a continuación:Además, tomaré críticas constructivas sobre mi estilo de codificación si tienes algo que ofrecer (a todos los lectores que se encuentren con esta pregunta) pero por favor mantenlo constructivo;) ... Si realmente me quieres, encuéntrame aquí en la sala de chat . Esperemos que con este fragmento de código se pueda ver cómo pueden usar el
List<Current>
como lo tengo definido como una tabla en el db y aList<T>
en su aplicación.fuente
Yo iría con la propuesta n. ° 1 o, como alternativa, crearía una tabla de borrador que solo contenga identificadores procesados. Inserte en esa tabla durante el procesamiento, luego, una vez terminado, llame a un proceso similar al siguiente:
Hará muchas inserciones, pero estarán en una mesa pequeña, por lo que debería ser rápido. También puede agrupar sus insertos usando ADO.net o cualquier adaptador de datos que esté utilizando.
fuente
El título de la pregunta incluye la tarea de transmitir datos desde una aplicación al procedimiento almacenado. Esa parte está excluida por el cuerpo de la pregunta, pero permítanme tratar de responderla también.
En el contexto de sql-server-2008 según lo especificado por las etiquetas, hay otro gran artículo de E. Sommarskog Arrays and Lists en SQL Server 2008 . Por cierto, lo encontré en el artículo al que se refería Marian en su respuesta.
En lugar de simplemente dar el enlace, cito su lista de contenido:
Más allá de las técnicas mencionadas allí, tengo la sensación de que, en algunos casos, la copia masiva y el inserto a granel merecen ser mencionados al alcance del caso general.
fuente
Para MS SQL 2016 última versión
Con MS SQL 2016 introducen una nueva función: SPLIT_STRING () para analizar múltiples valores.
Esto puede resolver su problema fácilmente.
Para la versión anterior de MS SQL
Si está utilizando una versión anterior, siga este paso:
Primero haz una función:
Después de hacer esto, simplemente pase su cadena a esta función con separador.
Espero que esto te sea útil. :-)
fuente
Use esto para crear "crear tabla de tipos". ejemplo simple para el usuario
fuente