sql >> Base de Datos >  >> RDS >> Mysql

Las tablas enormes de MySQL JOIN hacen que la base de datos colapse

300k filas no es una tabla enorme. Con frecuencia vemos tablas de 300 millones de filas.

El mayor problema con su consulta es que está utilizando una subconsulta correlacionada, por lo que tiene que volver a ejecutar la subconsulta para cada fila en la consulta externa.

Suele ocurrir que no es necesario hacer todo su trabajo en una instrucción SQL. Hay ventajas en dividirlo en varias declaraciones SQL más simples:

  • Más fácil de codificar.
  • Más fácil de optimizar.
  • Más fácil de depurar.
  • Más fácil de leer.
  • Más fácil de mantener si tiene que implementar nuevos requisitos.

Número de compras

SELECT customer, COUNT(sale) AS number_of_purchases
FROM sales 
GROUP BY customer;

Un índice de ventas (cliente, venta) sería mejor para esta consulta.

Valor de la última compra

Este es el greatest-n-per-group problema que surge con frecuencia.

SELECT a.customer, a.sale as max_sale
FROM sales a
LEFT OUTER JOIN sales b
 ON a.customer=b.customer AND a.dates < b.dates
WHERE b.customer IS NULL;

En otras palabras, intente hacer coincidir la fila a a una fila hipotética b que tiene el mismo cliente y una fecha mayor. Si no se encuentra esa fila, entonces a debe tener la mayor fecha para ese cliente.

Un índice de ventas (cliente, fechas, venta) sería mejor para esta consulta.

Si puede tener más de una venta para un cliente en esa fecha más importante, esta consulta devolverá más de una fila por cliente. Necesitarías encontrar otra columna para romper el empate. Si usa una clave principal de incremento automático, es adecuada como desempate porque se garantiza que es única y tiende a aumentar cronológicamente.

SELECT a.customer, a.sale as max_sale
FROM sales a
LEFT OUTER JOIN sales b
 ON a.customer=b.customer AND (a.dates < b.dates OR a.dates = b.dates and a.id < b.id)
WHERE b.customer IS NULL;

Importe Total de Compras, Cuando Tiene Valor Positivo

SELECT customer, SUM(sale) AS total_purchases
FROM sales
WHERE sale > 0
GROUP BY customer;

Un índice de ventas (cliente, venta) sería mejor para esta consulta.

Debería considerar usar NULL para indicar un valor de venta faltante en lugar de -1. Las funciones agregadas como SUM() y COUNT() ignoran los NULL, por lo que no tiene que usar una cláusula WHERE para excluir filas con venta <0.

Re:tu comentario

Los cinco principales clientes del cuarto trimestre de 2012

SELECT customer, SUM(sale) AS total_purchases
FROM sales
WHERE (year, quarter) = (2012, 4) AND sale > 0
GROUP BY customer
ORDER BY total_purchases DESC
LIMIT 5;

Me gustaría probarlo con datos reales, pero creo que un índice de ventas (año, trimestre, cliente, venta) sería lo mejor para esta consulta.

Última compra para clientes con compras totales> 5

SELECT a.customer, a.sale as max_sale
FROM sales a
INNER JOIN sales c ON a.customer=c.customer
LEFT OUTER JOIN sales b
 ON a.customer=b.customer AND (a.dates < b.dates OR a.dates = b.dates and a.id < b.id)
WHERE b.customer IS NULL
GROUP BY a.id
HAVING COUNT(*) > 5;

Al igual que en la otra consulta anterior de n mayor por grupo, un índice de ventas (cliente, fechas, venta) sería lo mejor para esta consulta. Probablemente no pueda optimizar tanto la unión como el grupo, por lo que generará una tabla temporal. Pero al menos solo hará una tabla temporal en lugar de muchas.

Estas consultas son lo suficientemente complejas. No debe intentar escribir una sola consulta SQL que pueda dar todas de estos resultados. Recuerde la cita clásica de Brian Kernighan: