Pergunta

Ok, aqui está uma consulta que estou executando agora em uma tabela que tem 45.000 registros e é 65 MB de tamanho ... e está prestes a ficar maior e maior (então eu tenho que pensar no desempenho futuro, bem aqui ):

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 como você pode ou não pode imaginar - ele se engasga o servidor mysql a um impasse ...

O que ele faz é - ele simplesmente puxa o número de novos usuários que se inscreveram, têm pelo menos um "completo" de pagamento, tm_completed não está vazio (uma vez que só é preenchida para pagamentos concluídos), e (Selecionar incorporado) esse membro nunca teve um pagamento "concluído" antes - o que significa que ele é um novo membro (só porque o sistema faz rebills e outros enfeites, e esta é a única maneira de tipo de diferenciar entre um membro existente que acabou rebilled e um novo membro que foi cobrado para a primeira vez).

Agora, existe alguma maneira possível otimizar essa consulta para usar menos recursos ou algo assim, e para parar de tomar os meus recursos mysql de joelhos ...?

Estou faltando alguma informação para esclarecer mais esta questão? Deixe-me saber ...

EDIT:

Aqui estão os índices já nessa tabela:

Primary Primary 46.757 payment_id

INDEX member_id 23378 member_id

payer_id INDEX 11689 payer_id

INDEX coupon_id 1 coupon_id

tm_added INDEX 46.757 tm_added, product_id

tm_completed INDEX 46.757 tm_completed, product_id

Foi útil?

Solução

Esses tipos de subqueries IN são um pouco lento no MySQL. Gostaria de reformulá-la assim:

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

A verificação 'tm_completed IS NOT NULL' não é necessário que o que está implícito por sua condição BETWEEN.

Também verifique se você tem um índice em:

(tm_completed, completed)

Outras dicas

Eu me diverti montar esta solução que não requer uma subconsulta:

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;

Evite usar IN com uma subconsulta; O MySQL não otimizá-los bem (apesar de existirem pendentes otimizações em 5,4 e 6,0 em relação a este (ver aqui ) Reescrevendo isso como uma junção provavelmente irá obter um aumento de desempenho:

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

Em segundo lugar, eu teria que ver o seu esquema de tabela; você está usando índices?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top