Domanda

Ok, ecco una query che io sono in esecuzione in questo momento su una tabella che ha 45.000 record ed è 65 MB di dimensioni ... ed è solo per ottenere più grande e più grande (così io devo pensare al futuro prestazioni pure qui ):

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)

E come si potrebbe o non potrebbe immaginare - si soffoca il server MySQL a un punto morto ...

Ciò che fa è - tira semplicemente il numero di nuovi utenti che si sono iscritti, hanno almeno un "completato" il pagamento, tm_completed non è vuota (come è popolato solo per i pagamenti completati), e (Select incorporato) questo membro ha mai avuto un pagamento "a termine" prima - il che significa che è un nuovo membro (solo perché il sistema fa rebills e quant'altro, e questo è l'unico modo per differenziare sorta di tra un utente esistente che ha appena rebilled e un nuovo membro che ma ho fatturato per la prima volta).

Ora, non v'è alcun modo possibile per ottimizzare questa query per utilizzare meno risorse o qualcosa del genere, e di smettere di prendere le mie risorse di MySQL in ginocchio ...?

mi manca qualsiasi informazione per chiarire questo ulteriore? Fatemi sapere ...

EDIT:

Qui ci sono gli indici già su quel tavolo:

PRIMARIA PRIMARY 46757 payment_id

member_id INDICE 23378 member_id

payer_id INDEX 11689 payer_id

coupon_id INDICE 1 coupon_id

Indice tm_added 46757 tm_added, product_id

Indice tm_completed 46757 tm_completed, product_id

È stato utile?

Soluzione

Questo tipo di subquery IN sono un po 'lento in MySQL. Vorrei riformulare in questo modo:

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');

Il controllo 'tm_completed IS NOT NULL' non è necessaria in quanto ciò è implicito dalla sua condizione BETWEEN.

assicurarsi di avere un indice anche:

(tm_completed, completed)

Altri suggerimenti

Mi sono divertita a mettere insieme questa soluzione che non richiede una sottoquery:

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;

Evitare di utilizzare IN con una sottoquery; MySQL non ottimizza questi bene (anche se ci sono ottimizzazioni in sospeso in 5.4 e 6.0 per quanto riguarda questo (vedi qui ) riscrittura questo come un join probabilmente vi ottenere un incremento delle prestazioni:.

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

In secondo luogo, avrei dovuto vedere il tuo schema della tabella; stai usando gli indici?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top