2009-12-08 68 views
82

Duplicar posible:
T-SQL WHERE col IN (…)Tamaño máximo para una consulta de SQL Server? Cláusula IN? ¿Hay un mejor enfoque

¿Cuál es el tamaño máximo para una consulta de SQL Server? (Nº de caracteres)

¿Tamaño máximo para una cláusula IN? Creo que vi algo acerca de que Oracle tiene un límite de 1000 artículos, pero se puede solucionar esto con ANDing 2 INs juntos. ¿Problema similar en SQL Server?

ACTUALIZACIÓN Entonces, ¿cuál sería el mejor enfoque si necesito tomar decir 1000 GUID de otro sistema (base de datos no relacionales) y hacer un "JOIN en código' contra el servidor SQL Server? ¿Es para presentar la lista de 1000 GUID a una cláusula IN? O hay otra técnica que funciona de manera más eficiente?

no he probado esto, pero me pregunto si podía presentar los GUID como un documento XML. Por ejemplo

<guids> 
    <guid>809674df-1c22-46eb-bf9a-33dc78beb44a</guid> 
    <guid>257f537f-9c6b-4f14-a90c-ee613b4287f3</guid> 
</guids> 

y luego haga algún tipo de XQuery JOIN contra el Doc y la Mesa. ¿Menos eficiente que la cláusula IN de 1000 elementos?

+1

parece ser un duplicado de: http: // stackoverflow. com/questions/1069415/t-sql-where-col-in – Yishai

+0

Permítanme agregar a la pregunta para hacerla más única. ver actualización – BuddyJoe

+1

recurso que encontré discutiendo algunas ideas - http://www.sommarskog.se/arrays-in-sql-2005.html#InsertMany – BuddyJoe

Respuesta

64

Cada lote SQL tiene que caber en el Batch Size Limit: 65,536 * Tamaño del paquete de red.

Aparte de eso, su consulta está limitada por las condiciones de tiempo de ejecución. Por lo general, se quedará sin tamaño de pila porque x IN (a, b, c) no es más que x = a OR x = b OR x = c, que crea un árbol de expresiones similar a x = a OR (x = b OR (x = c)), por lo que se pone muy profundo con una gran cantidad de OR. SQL 7 llegaría a SO at about 10k values in the IN, pero ahora las pilas son mucho más profundas (debido a x64), por lo que puede llegar a ser bastante profundo.

actualización

encontrado ya el artículo de Erland sobre el tema de pasar listas/matrices para SQL Server. Con SQL 2008 también tiene Table Valued Parameters que le permite pasar un DataTable completo como parámetro de tipo de tabla única y unirse a él.

XML y XPath es otra solución viable:

SELECT ... 
FROM Table 
JOIN (
    SELECT x.value(N'.',N'uniqueidentifier') as guid 
    FROM @values.nodes(N'/guids/guid') t(x)) as guids 
ON Table.guid = guids.guid; 
+0

"tamaño de pila": ese es el error que no pude recordar – gbn

12

por lote, 65536 * Network Packet Size que es por lo 4k 256 MB

Sin embargo, en detendrá mucho antes de eso, pero no es preciso.

Usted termina con errores de memoria pero no recuerdo el error exacto. Una IN enorme será ineficaz de todos modos.

Editar: Remus me recordó: el error es de un "tamaño de la pila"

34

Los Máximos de SQL Server se describen http://msdn.microsoft.com/en-us/library/ms143432.aspx (esta es la versión de 2008)

Una consulta SQL puede ser un varchar (max) pero se muestra como limitado a un tamaño de paquete de red de 65.536 *, pero incluso entonces lo más probable es que se tropiece con los 2100 parámetros por consulta. Si SQL elige parametrizar los valores literales en la cláusula in, creo que alcanzaría ese límite primero, pero no lo he probado.

Editar: Pruébelo, incluso bajo la parametrización forzada que sobrevivió - Cogí una prueba rápida y lo tenía ejecutando con 30k elementos dentro de la cláusula In. (SQL Server 2005)

En 100k artículos, se tomó un tiempo y luego cayó con:

Mensaje 8623, nivel 16, estado 1, línea 1 El procesador de consultas se quedó sin recursos internos y no pudo producir un plan de consulta. Este es un evento raro y solo esperado para consultas o consultas extremadamente complejas que hacen referencia a una gran cantidad de tablas o particiones. Por favor, simplifique la consulta. Si cree que recibió este mensaje por error, comuníquese con Servicios de soporte al cliente para obtener más información.

Así 30k es posible, pero sólo porque puede hacerlo - no quiere decir que usted debe :)

Editar: Continúa debido a la pregunta adicional.

50k funcionó, pero se cayeron 60k, por lo que en algún lugar de mi plataforma de prueba por cierto.

En términos de cómo hacer eso para unir los valores sin usar una cláusula grande, personalmente crearía una tabla temporal, insertaría los valores en esa tabla temporal, la indexaría y luego la usaría en una combinación, dándole las mejores oportunidades para optimizar las uniones. (Generar el índice en la tabla temporal creará estadísticas para él, lo que ayudará al optimizador como regla general, aunque 1000 GUIDs no encontrarán las estadísticas demasiado útiles.)

+1

ver la actualización. gracias por probar +1 – BuddyJoe

+0

Desafortunadamente estas consultas estarían ocurriendo regularmente. Por lo tanto, no creo que la indexación de la tabla temporal sea posible. Y para las inserciones máximas rápidas, la tabla principal se indexará mediante un int 'addid' (no se indexará en el GUID). Esto es más complicado de lo que pensaba. – BuddyJoe

+1

Se arriesga a una ligera optimización prematura: necesita obtener algunas figuras instrumentadas difíciles en términos de planes de consultas para su carga de trabajo, ya que será difícil modelar. Una vez que conozca las cifras de varios enfoques, puede hacer una elección, pero insertar 1k filas en una tabla temporal de SQL se puede hacer excepcionalmente rápido, realmente depende de cómo y qué lo está impulsando. – Andrew

7

¿Puede cargar los GUID en una tabla de cero luego hacer un

... WHERE var IN SELECT guid FROM #scratchtable 
+0

Si supone que tendrá estas consultas cada segundo o dos. Me pregunto cómo se mantendría la mesa de scratch. – BuddyJoe

+2

Utilizamos esta técnica extensivamente en nuestra aplicación y parece funcionar bien. Tempdb necesita ser grande y hacemos algunos ajustes en la instalación; no conozco los detalles de eso. Tempdb sí se ocupa. – DaveE

Cuestiones relacionadas