Pregunta

Ok, aquí está una consulta que estoy corriendo en este momento en una tabla que tiene 45.000 registros y es 65 MB de tamaño ... y está a punto de conseguir más grande y más grande (por lo que tengo que pensar en el futuro rendimiento, así que aquí ):

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL
AND member_id NOT IN (SELECT p2.member_id FROM payments p2 WHERE p2.completed=1 AND p2.tm_completed < '2009-05-01' AND p2.tm_completed IS NOT NULL GROUP BY p2.member_id)

Y a medida que podría o no podría imaginar - que ahoga el servidor MySQL a un punto muerto ...

Lo que hace es - es simplemente tira el número de nuevos usuarios que se inscribieron, tienen al menos una "completa" de pago, tm_completed no está vacío (ya que sólo está poblada por los pagos completados), y (Select incrustado) ese miembro no ha tenido nunca un pago "completado" antes - lo que significa que es un nuevo miembro (sólo porque el sistema hace rebills y todo eso, y esta es la única forma de tipo de diferenciar entre un miembro existente que acaba de conseguir vuelve a facturar y un nuevo miembro que consiguió facturado por primera vez).

Ahora, ¿hay alguna manera posible optimizar esta consulta para utilizar menos recursos o algo así, y para dejar de tomar los recursos de MySQL de rodillas ...?

Me estoy perdiendo ninguna información para aclarar más este asunto? Avisadme ...

EDIT:

Estos son los índices que ya en esa tabla:

PRIMARIA PRIMARIA 46757 payment_id

member_id ÍNDICE 23378 member_id

payer_id ÍNDICE 11689 payer_id

coupon_id ÍNDICE 1 coupon_id

ÍNDICE tm_added 46757 tm_added, product_id

ÍNDICE tm_completed 46757 tm_completed, product_id

¿Fue útil?

Solución

Este tipo de subconsultas IN son un poco lentos en MySQL. Me gustaría reformular así:

SELECT COUNT(1) AS signup_count, SUM(amount) AS signup_amount
FROM   payments p
WHERE  tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND    completed > 0
AND    NOT EXISTS (
           SELECT member_id
           FROM   payments
           WHERE  member_id = p.member_id
           AND    completed = 1
           AND    tm_completed < '2009-05-01');

El cheque 'tm_completed IS NOT NULL' no es necesario ya que está implícito en su condición BETWEEN.

También asegúrese de que tiene un índice en:

(tm_completed, completed)

Otros consejos

Me divertí armar esta solución que no requiere una sub consulta:

SELECT count(p1.payment_id) as signup_count, 
       sum(p1.amount)       as signup_amount  

  FROM payments p1
       LEFT JOIN payments p2 
       ON p1.member_id = p2.member_id
   AND p2.completed = 1
   AND p2.tm_completed < date '2009-05-01'

 WHERE p1.completed > 0
   AND p1.tm_completed between date '2009-05-01' and date '2009-05-30'
   AND p2.member_id IS NULL;

Evitar el uso de IN con una subconsulta; MySQL no optimiza estas bien (aunque hay pendientes optimizaciones en 5,4 y 6,0 con respecto a este (ver aquí ) Reescribiendo esto como una unión probablemente se obtiene un aumento de rendimiento:.

SELECT count(payment_id) as signup_count, sum(amount) as signup_amount
FROM payments p
LEFT JOIN (SELECT p2.member_id
          FROM payments p2
          WHERE p2.completed=1
          AND p2.tm_completed < '2009-05-01'
          AND p2.tm_completed IS NOT NULL
          GROUP BY p2.member_id) foo
ON p.member_id = foo.member_id AND foo.member_id IS NULL
WHERE tm_completed BETWEEN '2009-05-01' AND '2009-05-30'
AND completed > 0
AND tm_completed IS NOT NULL

En segundo lugar, tendría que ver el esquema de la tabla; está usando índices?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top