2015-09-21 2 views
0

В любом случае, чтобы оптимизировать этот запрос для MySQL 5.1?MySQL Оптимизация avg, запрос суммы остались вложенными вложенными select

У меня есть таблица «Calls», есть поля «Caller» (от номера), «Callee» (до номера) и «Duration», этот запрос отлично работает в SQLite, но он очень медленный в MySQL с огромными данными 14 миллиардов записей.

У меня есть указатель на поле Caller.

select A.Caller, ifnull(aCallOut, 0) as CallOut, round((ifnull(aDuration, 0)/60), 2) as Duration, round((ifnull(aAverage, 0)/60), 2) as Average, Times, 0, 0, 0, 0 
from 
    (
    select Caller, sum(duration) as aDuration, count(*) Times -- sum of duration of each caller 
    from Calls 
    group by Caller 
) As A 

left join 
    (
    select Caller, avg(duration) as aAverage -- i want avg duration of numbers that calling more than 0 seconds 
    from Calls 
    where Duration > 0 
    group by Caller 
) as C 
    on A.Caller = C.Caller 

left join 
    (
    select Caller, count(*) as aCallOut -- i need to count how many numbers that caller called, ignoring the duplicating calls 
    from 
     (
     select Caller, count(*) aCount 
     from Calls 
     group by Caller, Callee 
    ) as D 
    group by Caller 
) as B 
    on A.Caller = B.Caller 
+0

Первые два могут быть объединены достаточно просто, но мне трудно понять точку третьей части; 'Callee' больше нигде не упоминается, не используется в соединении, и нет никаких сумм слияния (суммы, среднего и т. Д.) Нескольких вызываемых абонентов на вызывающем абоненте, к которому они присоединились. – Uueerdo

+0

Ничего, ответ Гордона ниже дает это более ясный. – Uueerdo

ответ

1

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

select Caller, sum(duration) as aDuration, count(*) as Times, 
     avg(case when duration > 0 then duration end) as aAverage, 
     count(distinct Callee) as aCallOut 
from Calls 
group by Caller; 

Небольшое замечание: если Callee когда-либо NULL, то aCallOut может быть смещена на 1.

+0

«Если значение when_value или search_condition не соответствует проверенному значению, а оператор CASE не содержит предложение ELSE, то не обнаружен случай, не найденный для ошибки оператора CASE». Https://dev.mysql.com/doc/refman/5.0/en/case .html – Uueerdo

+0

@Uueerdo. , , Вы сбиваете с толку инструкцию 'case' с выражением 'case' стандартного ANSI. Выражение 'case' не требует предложения' ELSE' (см. Https://dev.mysql.com/doc/refman/5.6/en/control-flow-functions.html#operator_case). –

+0

Ах, моя ошибка ... и некоторые быстрые тесты подтверждают, что AVG игнорирует NULL. Также подтверждено, что SUM также, я мог бы поклялся, что SUM используется для возврата NULL, если какое-либо значение было обработано NULL ... – Uueerdo

0

Чтобы объединить первые два ...

SELECT Caller 
, sum(duration) as aDuration -- sum of duration of each caller 
, count(*) Times 
, SUM(IF(duration>0, duration, 0))/NULLIF(SUM(IF(duration>0, 1, 0)),0) -- avg(duration) as aAverage 
FROM Calls 
GROUP BY Caller 

Редактировать: У этого может быть разрыв по нулевой ошибке, если у вызывающего абонента нет строк duration > 0.

Редактировать # 2: Обертка знаменателя в NULLIF(,0) предотвращает эту ошибку.

Смежные вопросы