¿Qué es más rápido, una consulta grande o muchas consultas pequeñas?

68

He estado trabajando para diferentes compañías, y he notado que algunas de ellas prefieren tener puntos de vista que se unirán a una mesa con todos sus "familiares". Pero luego, en la aplicación algunas veces, solo necesitamos usar solo 1 columna.

Entonces, ¿sería más rápido hacer selecciones simples y luego "unirlas" en el código del sistema?

El sistema podría ser php, java, asp, cualquier idioma que se conecte a la base de datos.

Entonces, la pregunta es, ¿qué pasa más rápido desde un lado del servidor (php, java, asp, ruby, python ...) a la base de datos? Ejecute una consulta que obtenga todo lo que necesitamos o vaya del lado del servidor a la base de datos y ejecute un consulta que solo obtiene las columnas de una tabla a la vez?

sudo.es
fuente
2
¿Qué implementación de 'SQL' estás usando? MySQL, Microsoft SQL Server, Oracle, Postgresql, etc. Por favor actualice su etiqueta.
RLF
1
Mysql y Postgresql
sudo.ie
66
Mi experiencia es que a MySQL no le gustan las consultas complicadas y generalmente es más rápido con consultas muy simples (pero más). El optimizador de consultas de Postgres es mucho mejor y, por lo general, es más eficiente ejecutar una sola consulta grande.
a_horse_with_no_name
3
@a_horse_with_no_name Esa es una generalización muy amplia, especialmente en el contexto de esta pregunta. El optimizador MySQL es de hecho muy simple por diseño, y puede causar problemas con las uniones y subconsultas, especialmente en versiones anteriores de MySQL, que de otro modo han producido planes más rápidos en PostgreSQL, mientras que MySQL puede ser muy rápido para cargas OLTP puras. Sin embargo, en el contexto de la pregunta, una sola consulta grande será más rápida que, digamos, en el peor escenario posible, un SELECT dentro de un bucle de programación (sin importar el RDBMS utilizado).
jynus
2
@jynus: bueno, la pregunta es muy amplia (además: dije "en mi experiencia", otras personas podrían tener experiencias diferentes). Una consulta dentro de un LOOP nunca es una buena idea y casi siempre es el resultado de un diseño deficiente o falta de comprensión sobre cómo trabajar con una base de datos relacional.
a_horse_with_no_name

Respuestas:

69

Lo que abordaría su pregunta es el tema ÚNASE A LA DESCOMPOSICIÓN.

De acuerdo con la página 209 del libro

MySQL de alto rendimiento

Puede descomponer una combinación ejecutando múltiples consultas de tabla única en lugar de una combinación multitarea y luego realizando la combinación en la aplicación. Por ejemplo, en lugar de esta consulta única:

SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id = tag.id
JOIN post ON tag_post.post_id = post.id
WHERE tag.tag = 'mysql';

Puede ejecutar estas consultas:

SELECT * FROM tag WHERE tag = 'mysql';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN (123,456,567,9098,8904);

¿Por qué demonios harías esto? A primera vista, parece un desperdicio, porque ha aumentado el número de consultas sin obtener nada a cambio. Sin embargo, tal reestructuración en realidad puede brindar importantes ventajas de rendimiento:

  • El almacenamiento en caché puede ser más eficiente. Muchas aplicaciones almacenan en caché los "objetos" que se asignan directamente a las tablas. En este ejemplo, si el objeto con la etiqueta mysqlya está en caché, la aplicación omitirá la primera consulta. Si encuentra publicaciones con un ID de 123, 567 o 908 en la memoria caché, puede eliminarlas de la IN()lista. El caché de consultas también podría beneficiarse de esta estrategia. Si solo una de las tablas cambia con frecuencia, descomponer una unión puede reducir el número de invalidaciones de caché.
  • Ejecutar las consultas individualmente a veces puede reducir la contención de bloqueo
  • Hacer uniones en la aplicación hace que sea más fácil escalar la base de datos al colocar tablas en diferentes servidores.
  • Las consultas en sí mismas pueden ser más eficientes. En este ejemplo, el uso de una IN()lista en lugar de una combinación permite a MySQL ordenar las ID de fila y recuperar filas de manera más óptima de lo que podría ser posible con una combinación.
  • Puede reducir los accesos a filas redundantes. Hacer una unión en la aplicación significa recuperar cada fila solo una vez, mientras que una unión en la consulta es esencialmente una desnormalización que puede acceder repetidamente a los mismos datos. Por la misma razón, dicha reestructuración también podría reducir el tráfico total de la red y el uso de memoria.
  • Hasta cierto punto, puede ver esta técnica como la implementación manual de una combinación hash en lugar del algoritmo de bucles anidados que MySQL usa para ejecutar una combinación. Una combinación hash podría ser más eficiente.

Como resultado, las uniones de acciones en la aplicación pueden ser más eficientes cuando almacena en caché y reutiliza una gran cantidad de datos de consultas anteriores, distribuye datos en varios servidores, reemplaza las uniones por IN()listas o una unión hace referencia a la misma tabla varias veces.

OBSERVACIÓN

Me gusta la primera viñeta porque InnoDB es un poco pesado cuando verifica la caché de consultas.

En cuanto al último punto, escribí una publicación el 11 de marzo de 2013 ( ¿Hay una diferencia de ejecución entre una condición JOIN y una condición WHERE? ) Que describe el algoritmo de bucle anidado. Después de leerlo, verá cuán buena puede ser la descomposición de unión.

En cuanto a todos los demás puntos del libro , los desarrolladores realmente buscan el rendimiento como resultado final. Algunos confían en medios externos (fuera de la aplicación) para mejorar el rendimiento, como usar un disco rápido, obtener más CPU / núcleos, ajustar el motor de almacenamiento y ajustar el archivo de configuración. Otros se abrocharán y escribirán un mejor código. Algunos pueden recurrir a la codificación de toda la inteligencia empresarial en los Procedimientos almacenados, pero aún así no aplican la descomposición conjunta (consulte ¿Cuáles son los argumentos en contra o para poner la lógica de la aplicación en la capa de la base de datos? Junto con las otras publicaciones). Todo depende de la cultura y la tolerancia de cada tienda de desarrolladores.

Algunos pueden estar satisfechos con el rendimiento y no tocar más el código. Otros simplemente no se dan cuenta de que hay grandes beneficios que uno puede cosechar si intentan unir la composición.

Para aquellos desarrolladores que estén dispuestos ...

DARLE UNA OPORTUNIDAD !!!

RolandoMySQLDBA
fuente
3
En cuanto a ese enlace sobre cambiar a 3 consultas ... Conozco y respeto a Barón, Vadim y Peter, pero no estoy de acuerdo con esta sugerencia engañosa. La mayoría de los argumentos a favor de la separación son tan raros que no vale la pena mencionarlos. Quédese con una sola consulta con JOINs, luego trabajemos para mejorarla.
Rick James
2
@ RickJames Estoy de acuerdo con el espíritu de tu comentario. A lo largo de los años, he visto unir la descomposición para algunos y fallar para otros. Incluso con el conjunto de habilidades SQL adecuado, podría funcionar en su contra si la descomposición de la unión no se realiza correctamente. En mi empleador actual, a muchos departamentos les encanta escalar y escalar, especialmente cuando el código heredado está involucrado y hay bolsillos profundos disponibles. Con aquellos que tienen sabor a caviar pero presupuestos de ensalada de huevo, la descomposición conjunta podría valer el riesgo, pero debe hacerse bien.
RolandoMySQLDBA
Me encantaría ver cómo funciona esto en un entorno Oracle si tuviera los derechos y el tiempo.
Rick Henderson
Otra forma en que puede ser más rápido es que si está haciendo un pedido, será menos cálculos en general ordenar listas más pequeñas que ordenar una lista grande.
Evan Siroky
24

En Postgres (y probablemente cualquier RDBMS en un grado similar, MySQL en menor medida), menos consultas son casi siempre mucho más rápidas.

La sobrecarga de analizar y planificar múltiples consultas ya es más que cualquier ganancia posible en la mayoría de los casos.

Por no hablar del trabajo adicional que se debe hacer en el cliente, combinando los resultados, que generalmente es mucho más lento. Un RDBMS se especializa en ese tipo de tarea y las operaciones se basan en tipos de datos originales. No hay que enviar texty volver resultados intermedios ni transformarlos en tipos nativos del cliente, lo que puede incluso conducir a resultados menos correctos (¡o incorrectos!). Piensa en números de coma flotante ...

También transfiere más datos entre el servidor DB y el cliente. Esto puede ser insignificante para una mano llena de valores, o hacer una gran diferencia.

Si las consultas múltiples significan múltiples viajes de ida y vuelta al servidor de la base de datos, también recopila varias veces la latencia de la red y la sobrecarga de la transacción, posiblemente incluso la sobrecarga de la conexión. Gran, gran pérdida.

Dependiendo de su configuración, la latencia de la red por sí sola puede tomar más tiempo que el resto por orden de magnitud.

Pregunta relacionada sobre SO:

Puede haber un punto de inflexión para consultas muy grandes y de larga duración porque las transacciones recopilan bloqueos en las filas de la base de datos en el camino. Las consultas muy grandes pueden contener muchos bloqueos durante un período prolongado de tiempo, lo que puede causar fricción con las consultas concurrentes .

Erwin Brandstetter
fuente
Solo por curiosidad, ¿qué consideras muy grande ?
Sablefoste
@Sablefoste: Mucho depende de sus patrones de acceso. Un punto crítico es donde las transacciones concurrentes comienzan a hacer cola, esperando que se liberen los bloqueos, o si acumula suficientes bloqueos para comer una parte sustancial de sus recursos. O si sus consultas se ejecutan el tiempo suficiente para interferir con el vacío automático ...
Erwin Brandstetter
Pero si tomamos una situación algo típica: una consulta que utiliza una combinación externa y devuelve muchos datos redundantes para la tabla "principal", que luego debe analizarse y clasificarse por la aplicación (muy probablemente, alguna biblioteca ORM) versus un ¿Selección pequeña que recupera todas las ID requeridas primero y luego otra selección más pequeña con IN () en lugar de combinación externa? ¿El segundo enfoque no será más eficiente (teniendo en cuenta que tanto la base de datos como la aplicación consumieron CPU y ancho de banda de comunicaciones)?
JustAMartin
1
@JustAMartin: Eso suena como el tipo de consulta que casi seguramente es más rápida cuando la maneja el planificador de consultas del RDBMS, suponiendo consultas correctas. En cuanto a returns lots of redundant data for "parent" table: ¿Por qué devolvería datos redundantes? Solo devuelva los datos que necesita.
Erwin Brandstetter
1
Con la unión externa, RDBMS devuelve datos de la tabla primaria duplicados para cada elemento secundario unido, lo que significa una sobrecarga de red y memoria, y luego un análisis adicional en la herramienta ORM para descartar los valores primarios duplicados y mantener solo un elemento primario con n elementos secundarios. Por lo tanto, con una sola consulta ahorramos en el trabajo eficiente del planificador de consultas RDBMS, menos solicitudes de red (o canalización local) pero perdemos carga útil innecesaria adicional y desplazamos datos en la biblioteca ORM. Supongo que es como siempre: mida antes de optimizar.
JustAMartin