Límite práctico de la longitud de la consulta SQL (específicamente MySQL)

¿Es particularmente malo tener una consulta SQL muy grande con muchas cláusulas WHERE (potencialmente redundantes)?

Por ejemplo, aquí hay una consulta que he generado desde mi aplicación web con todo apagado, que debería ser la mayor consulta posible para que este programa genere:

SELECT * 
FROM 4e_magic_items 
INNER JOIN 4e_magic_item_levels 
  ON 4e_magic_items.id = 4e_magic_item_levels.itemid 
INNER JOIN 4e_monster_sources 
  ON 4e_magic_items.source = 4e_monster_sources.id 
WHERE (itemlevel BETWEEN 1 AND 30)  
  AND source!=16 AND source!=2 AND source!=5 
  AND source!=13 AND source!=15 AND source!=3 
  AND source!=4 AND source!=12 AND source!=7 
  AND source!=14 AND source!=11 AND source!=10 
  AND source!=8 AND source!=1 AND source!=6 
  AND source!=9  AND type!='Arms' AND type!='Feet' 
  AND type!='Hands' AND type!='Head' 
  AND type!='Neck' AND type!='Orb' 
  AND type!='Potion' AND type!='Ring' 
  AND type!='Rod' AND type!='Staff' 
  AND type!='Symbol' AND type!='Waist' 
  AND type!='Wand' AND type!='Wondrous Item' 
  AND type!='Alchemical Item' AND type!='Elixir' 
  AND type!='Reagent' AND type!='Whetstone' 
  AND type!='Other Consumable' AND type!='Companion' 
  AND type!='Mount' AND (type!='Armor' OR (false )) 
  AND (type!='Weapon' OR (false )) 
 ORDER BY type ASC, itemlevel ASC, name ASC

Parece funcionar bastante bien, pero tampoco es un tráfico particularmente intenso (unos cientos de visitas al día más o menos), y me pregunto si valdría la pena intentar optimizar las consultas para eliminar redundancias y cosas así.

0
agregado editado
Puntos de vista: 1
1. Gracias por responder la pregunta, creo que el tamaño de la consulta no debería ser un problema para mí ahora. 2. Gracias a todos por los consejos sobre cómo formatear el SQL. Soy nuevo en esto y hay muchos trucos que no sé (por ejemplo, "escriba no en (...)") 3. Solo como una adición, esta es una aplicación de PHP/MySQL
agregado el autor Asmor, fuente
Aquí hay un formateador SQL en línea útil: sqlinform.com
agregado el autor micahwittman, fuente
Cuando intentas usar el sitio web, ¿parece lento? Si solo hay unos cientos de visitas al día, supongo que no podría preocuparse por eso. ¿Esperas que el tráfico aumente? ¿Por cuanto? Si no tiene problemas de tiempo, puede hacerlo, para proteger el sitio en el futuro. Pero entonces, ¿es el tiempo que se tarda en encontrar y eliminar redundancias de forma programática más allá del tiempo que lleva ejecutar la consulta?
agregado el autor Matt Blaine, fuente

6 Respuestas

Leer su consulta me hace querer jugar un juego de rol.

Esto definitivamente no es demasiado largo. Siempre y cuando estén bien formateados, diría que un límite práctico es de aproximadamente 100 líneas. Después de eso, será mejor que rompas las subconsultas en vistas solo para evitar que tus ojos se crucen.

He trabajado con algunas consultas de más de 1000 líneas, y eso es difícil de depurar.

Por cierto, ¿puedo sugerir una versión reformateada? Esto es principalmente para demostrar la importancia del formateo; Confío en que esto será más fácil de entender.

select *  
from
  4e_magic_items mi
 ,4e_magic_item_levels mil
 ,4e_monster_sources ms
where mi.id = mil.itemid
  and mi.source = ms.id
  and itemlevel between 1 and 30
  and source not in(16,2,5,13,15,3,4,12,7,14,11,10,8,1,6,9)  
  and type not in(
                  'Arms' ,'Feet' ,'Hands' ,'Head' ,'Neck' ,'Orb' ,
                  'Potion' ,'Ring' ,'Rod' ,'Staff' ,'Symbol' ,'Waist' ,
                  'Wand' ,'Wondrous Item' ,'Alchemical Item' ,'Elixir' ,
                  'Reagent' ,'Whetstone' ,'Other Consumable' ,'Companion' ,
                  'Mount'
                 )
  and ((type != 'Armor') or (false))
  and ((type != 'Weapon') or (false))
order by
  type asc
 ,itemlevel asc
 ,name asc

/*
Some thoughts:
==============
0 - Formatting really matters, in SQL even more than most languages.
1 - consider selecting only the columns you need, not "*"
2 - use of table aliases makes it short & clear ("MI", "MIL" in my example)
3 - joins in the WHERE clause will un-clutter your FROM clause
4 - use NOT IN for long lists
5 - logically, the last two lines can be added to the "type not in" section.
    I'm not sure why you have the "or false", but I'll assume some good reason
    and leave them here.
*/
0
agregado
Para secundar el pensamiento de David B ... Mi experiencia es principalmente Oracle/SQL Server, y ninguno de los dos sufre la limitación que plantea Aeon. Si MySql realmente se comporta de esa manera, entonces definitivamente querrías mantener uniones en el FROM. Sugiero probarlo de ambas maneras y comparar los tiempos de ejecución.
agregado el autor JosephStyons, fuente
Eso es porque las armaduras (y las armas) se filtran más por tipo. Entonces, por ejemplo, si se seleccionan Cloth y Hide, se leería: (type! = 'Armor' O (FALSE O restricciones como 'C' O restricciones como 'H')) La página simplemente agrega "o Restrictions like 'whatever' "dentro de los parens, tan falso es necesario.
agregado el autor Asmor, fuente
las uniones en la cláusula FROM despejarán su cláusula WHERE. @Aeon: no debería haber diferencia de rendimiento con un optimizador de consultas adecuado. ¿Es eso tan malo?
agregado el autor Amy B, fuente
En realidad, las uniones acelerarán las cosas, especialmente con los índices adecuados. La razón es que si todas sus cláusulas están en DONDE, MySQL obtendrá todos los datos y luego los filtrará; mientras que con una combinación adecuada seleccionará solo los datos necesarios, que pueden ser algunos órdenes de magnitud más pequeños, más rápidos de filtrar.
agregado el autor Aeon, fuente
Ah, y ... A menos que me falta algo, (tipo! = 'Armadura' O (falso)) va a evaluar a verdadero, o falso, pero en cualquier caso no va a afectar el conjunto de resultados, por lo en realidad ni siquiera es necesario.
agregado el autor Aeon, fuente
downvote para abarrotar la cláusula WHERE con condiciones de JOIN.
agregado el autor longneck, fuente

¿Supongo que quieres decir con "apagado" que un campo no tiene un valor?

En lugar de verificar si algo no es esto, y tampoco es eso, ¿no puedes simplemente verificar si el campo es nulo? O establezca el campo en 'apagado' y verifique si tipo o lo que sea igual a 'apagado'.

0
agregado

La mayoría de las bases de datos admiten procedimientos almacenados para evitar este problema. Si su código es lo suficientemente rápido como para ejecutarse y es fácil de leer, no desea tener que cambiarlo para disminuir el tiempo de compilación.

Una alternativa es usar declaraciones preparadas para que solo reciba el hit una vez por cada conexión del cliente y luego solo ingrese los parámetros para cada llamada.

0
agregado

La limitación predeterminada del servidor MySQL 5.0 es " 1 MB ", configurable hasta 1 GB.

Esto se configura mediante la configuración max_allowed_packet en ambos cliente y servidor, y la limitación efectiva es el arrendador de los dos.

Advertencias:

  • Es probable que esta limitación de "paquete" no se asigne directamente a los caracteres en una declaración de SQL. Seguramente desea tener en cuenta la codificación de caracteres dentro del cliente, algunos metadatos de paquetes, etc.)
0
agregado

Desde una perspectiva práctica, generalmente considero que cualquier SELECCIÓN que termine tomando más de 10 líneas para escribir (poniendo cada cláusula/condición en una línea separada) es demasiado larga para mantenerla fácilmente. En este punto, probablemente debería hacerse como un procedimiento almacenado de algún tipo, o debería tratar de encontrar una forma mejor de expresar el mismo concepto, posiblemente mediante la creación de una tabla intermedia para capturar alguna relación que parece estar consultando con frecuencia.

Su kilometraje puede variar, y hay algunas consultas excepcionalmente largas que tienen una buena razón para estar. Pero mi regla de oro es 10 líneas.

Example (mildly improper SQL):

SELECT x, y, z
FROM a, b
WHERE fiz = 1
AND foo = 2
AND a.x = b.y
AND b.z IN (SELECT q, r, s, t
            FROM c, d, e
            WHERE c.q = d.r
              AND d.s = e.t
              AND c.gar IS NOT NULL)
ORDER BY b.gonk

Esto es probablemente demasiado grande; la optimización, sin embargo, dependería en gran medida del contexto.

Solo recuerde, cuanto más larga y compleja sea la consulta, más difícil será mantenerla.

0
agregado

SELECCIONE @@ global.max_allowed_packet

este es el único límite real que se puede ajustar en un servidor, por lo que no hay una respuesta real

0
agregado