Вопрос

Хорошо, вот запрос, который я выполняю прямо сейчас для таблицы, содержащей 45 000 записей и имеющей размер 65 МБ...и вот-вот станет все больше и больше (так что я должен подумать и о будущем выступлении здесь).:

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)

И, как вы можете себе представить, а можете и не представить, это приводит к остановке сервера mysql...

Что он делает - он просто извлекает количество новых пользователей, которые зарегистрировались, имеют по крайней мере один "завершенный" платеж, значение tm_completed не пустое (поскольку оно заполняется только для завершенных платежей), и (встроенный Select) у этого участника никогда раньше не было "завершенного" платежа - это означает, что он новый участник (просто потому, что система выполняет ребиллы и еще много чего, и это единственный способ провести различие между существующим участником, который только что получил ребиллинг, и новым участником, которому выставили счет в первый раз).

Итак, есть ли какой-либо возможный способ оптимизировать этот запрос, чтобы использовать меньше ресурсов или что-то в этом роде, и перестать ставить мои ресурсы mysql на колени ...?

Мне не хватает какой-либо информации, чтобы прояснить это еще больше?Дай мне знать...

Редактировать:

Вот индексы, которые уже есть в этой таблице:

ПЕРВИЧНЫЙ ПЕРВИЧНЫЙ 46757 payment_id

member_id ИНДЕКС 23378 member_id

payer_id ИНДЕКС 11689 payer_id

coupon_id ИНДЕКС 1 coupon_id

tm_added ИНДЕКС 46757 tm_added, product_id

tm_completed ИНДЕКС 46757 tm_completed, product_id

Это было полезно?

Решение

Такого рода IN подзапросы в MySQL работают немного медленно.Я бы перефразировал это так:

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

Чек 'tm_completed IS NOT NULL- в этом нет необходимости, поскольку это подразумевается вашим BETWEEN состояние.

Также убедитесь, что у вас есть индекс на:

(tm_completed, completed)

Другие советы

Мне было весело собирать это решение, которое не требует подзапроса:

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;

Избегайте использования IN с подзапросом;MySQL не очень хорошо их оптимизирует (хотя в 5.4 и 6.0 есть незавершенные оптимизации по этому поводу (см. здесь).Переписав это как join, вы, вероятно, повысите производительность:

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

Во-вторых, мне нужно было бы увидеть вашу схему таблицы;используете ли вы индексы?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top