Mi problema (o al menos el mensaje de error) es muy similar al del procesador de consultas que se quedó sin recursos internos: consulta SQL extremadamente larga .
Mi cliente está trabajando con una consulta de selección SQL, que contiene una cláusula where con exactamente 100,000 entradas.
La consulta falla con el error 8632 y el mensaje de error
Error interno: se ha alcanzado un límite de servicios de expresión. Busque expresiones potencialmente complejas en su consulta e intente simplificarlas).
Me resulta muy peculiar que este mensaje de error se arroje, exactamente a 100,000 entradas, así que me pregunto si este es un valor configurable. ¿Es este el caso y, en caso afirmativo, cómo puedo aumentar este valor a uno más alto?
En MSDN , existe la propuesta de reescribir la consulta, pero me gustaría evitar esto.
Mientras tanto, descubrí que la lista de entradas de la que estoy hablando contiene números naturales, algunos de ellos parecen ser secuenciales (algo así como (1,2,3,6,7,8,9,10,12, 13,15,16,17,18,19,20).
Esto hace que la cláusula where de SQL sea algo así como:
where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)
Podría transformar esto en:
where (entry between 1 and 3) OR
(entry between 6 and 10) OR
(entry between 12 and 13) OR
(entry between 15 and 20)
¿Puede esto ser acortado por:
where entry in (1,...,3,6,...,10,12,13,15,...,20)
...¿o algo similar? (Sé que es una posibilidad remota, pero haría las actualizaciones de software más fáciles y más legibles)
Para su información: los datos en la cláusula where son el resultado de un cálculo, realizado en otra tabla: primero las entradas de esa tabla se leen y se filtran al principio, luego se realiza un procesamiento adicional (que es imposible hacer usando SQL), el resultado de ese procesamiento adicional es más filtrado y el resultado se usa en la cláusula where. Como era imposible escribir el filtrado completo en SQL, se ha utilizado el método mencionado. Obviamente, el contenido de la cláusula where podría cambiar en cada procesamiento, de ahí la necesidad de una solución dinámica.
fuente
WHERE IN
no admite ese tipo de sintaxis de rango. Además, no debería serWHERE () OR () OR ()
AND. Pero para usar la sugerencia de Brent, en realidad no tiene que cambiar toda la consulta, simplemente puede hacerloWHERE IN (SELECT myID FROM #biglist)
. Y#biglist
podría ser una tabla real (permanente) o una tabla temporal que haga sobre la marcha.Respuestas:
Para buscar más de 100.000 valores, colóquelos en una tabla temporal, una fila por valor que esté buscando. Luego, une tu consulta a esa tabla temporal para filtrar.
Algo con más de 100,000 valores no es un parámetro, es una tabla. En lugar de pensar en aumentar el límite, considere la regla del diez por ciento de Swart : si se acerca al 10% del límite de SQL Server, probablemente lo pasará mal.
fuente
Si vas a cambiar la aplicación de todos modos, considera
(a) usando un TVP para todo el conjunto de valores: crearía un
DataTable
C # y lo pasaría a un procedimiento almacenado usandoStructuredType
, como lo demuestro aquí . (Esperemos que 100,000 entradas no sean normales, ya que la escalabilidad puede ser un problema sin importar el enfoque que use).o
(b) usar un TVP para pasar en los límites superior e inferior de los rangos, y escribir una unión ligeramente diferente (gracias @ypercube).
fuente
No, no es configurable y no puede aumentarlo a uno más alto.
Hay una solución sugerida en el artículo de MSDN que mencionó y otros artículos. Mencioné dos aquí, pero puedes buscar más.
fuente
Solo mis 2 ¢ con respecto a acortar la condición de consulta: -
Si puede determinar todos los valores posibles de
entry
antemano, ¿sería factible si toma el complemento de su consulta?antes de
Después
fuente
Es difícil darse cuenta de lo que está tratando de lograr sin poder ver realmente la consulta, pero aquí vamos, suponiendo que su consulta solo necesita dos tablas, una con los datos y otra con los valores que desea evitar:
where entry in (<list of 100.000 values>)
es escandalosamente horrible, tanto desde el punto de vista de la eficiencia como del mantenimiento.where entry in (select whatever from table)
es apenas tan atrozmente horrible como el anterior. Sin embargo, dependiendo de la idiosincrasia de ambas tablas y del motor SQL, podría funcionar bien a pesar del cáncer de córnea. (Puede estar bien en Oracle, nunca estará en MySQL, no puedo recordar acerca de MSSQL).En mi opinión (sin conocer la consulta), debe volver a escribir la consulta de la siguiente manera:
Si esos 100.000 valores son siempre los mismos, sin depender del resto de la consulta, debe cargar esos valores en una tabla (table_fixed_values) y usar
Si esos 100.000 valores no son los mismos, debe haber algún tipo de lógica para recoger esos 100.000 valores, lógica que debe incrustar en la
ON
consulta anterior.fuente
LEFT JOIN table_fixed_values ON A.entry=B.entry WHERE B.entry IS NOT NULL
y no el equivalente, más simple y más fácil de leerINNER JOIN table_fixed_values ON A.entry=B.entry
?