2012-01-26 2 views
0

У меня есть таблица телефонных событий от HomeId. Каждая строка имеет EventId (на крюке, выкл. Крюке, кольце, DTMF и т. Д.), TimeStamp, Sequence (автоинкремент) и HomeId. Im работает над запросом, чтобы найти конкретные типы вхождений (входящие или исходящие вызовы IE) и продолжительность.MySQL - оптимизация самостоятельного объединения

Я планировал сделать это, используя множественное самосоединение в этой таблице, чтобы выбрать последовательности событий, которые обычно указывают на один тип возникновения или другой. Входящие вызовы EG будут периодом бездействия, за которым следует DTMF, а затем звонит и идентификатор вызывающего абонента (возможно), а затем отключается. Я бы нашел следующий на крючок и, следовательно, имел продолжительность.

Моя таблица индексируется HomeId, EventId и Sequence и имеет записи ~ 60K. Когда я объясняю свой запрос, он показывает индексирование и 75, 75, 1, 1, 748 для подсчета строк. Кажется довольно выполнимым. Но когда я запускаю запрос, он занимает более 10 минут (в этот момент браузер запросов MySQL истекает).

запросов для исходящих вызовов:

select pe0.HomeId, pe1.Stamp, pe1.mSec, timediff(pe4.Stamp, pe0.Stamp) from Phone_Events pe0 
join Phone_Events pe1 on pe0.HomeId = pe1.HomeId and pe1.Sequence = pe0.Sequence - 1 and abs(timediff(pe0.Stamp, pe1.Stamp)) > 10 
join Phone_Events pe2 on pe0.HomeId = pe2.HomeId and pe2.Sequence = pe0.Sequence + 1 and pe2.EventId = 22 
join Phone_Events pe4 on pe4.HomeId = pe0.HomeId and pe4.EventId = 30 and pe4.Stamp > pe0.Stamp 
where pe0.eventId = 12 and pe0.HomeId = 111 
AND 
    NOT EXISTS(SELECT * FROM Phone_Events pe3 
       WHERE pe3.HomeId = pe0.HomeId 
       AND pe3.EventId not in(13, 22) 
       AND pe3.Stamp > pe0.Stamp and pe3.Stamp < pe4.Stamp); 

Есть ли что-то конкретное для себя соединения, что делает это медленно? Есть ли лучший способ оптимизировать это? Убийца, кажется, является частью «не существует» - эта часть там, чтобы убедиться, что между последним «на крюке» и текущим «выключенным крюком» нет событий.

EDIT: EVENTID в следующем виде:

'1', 'device connection' 
'2', 'device disconnection' 
'3', 'device alarm' 
'11', 'ring start' 
'12', 'off hook' 
'13', 'hang up(other end)' 
'15', 'missed call' 
'21', 'caller id' 
'22', 'dtmf' 
'24', 'device error' 
'30', 'on hook' 
'31', 'ring stop' 
+0

выглядит как индекс на штемпеле будет полезно – Randy

+0

Первичный ключ (последовательность, Home). Существуют также индексы (Sequence, Home), EventId и HomeId. – ethrbunny

+0

abs (timediff (pe0.Stamp, pe1.Stamp)) <- это не может быть хорошо для производительности. – JohnFx

ответ

1

полностью переписан на основе новой информации. Как я подошел к этому, нужно было начать с самого внутреннего запроса, чтобы все записи, о которых мы заботимся, основывались исключительно на HomeID = 111 и следили за тем, чтобы они были предварительно отсортированы по идентификатору последовательности (указатель на HomeID, Sequence). Как мы все знаем, телефонный звонок начинается, поднимая телефон - eventID = 12, получая гудок - eventid = 22, набирающий номер и кто-то, отвечающий, пока телефон не вернется на крючок - eventid = 30) , Если это зависание (eventid = 13), мы хотим игнорировать его.

Я не знаю, почему вы смотрите на последовательность # PRIOR на текущий вызов, не знаете, имеет ли он какой-либо подшипник. Похоже, вы просто пытаетесь получить завершенные звонки и как долго длится. Тем не менее, я бы удалил часть LEFT JOIN Phone_Event и соответствующее предложение WHERE. Возможно, это было, пока вы просто пытались понять это.

В любом случае, вернемся к логике. Внутреннее большинство гарантирует последовательность вызовов по порядку. У вас не будет двух одновременных вызовов. Поэтому, сначала получив их в порядке, я затем присоединяюсь к SQLVars (который создает встроенную переменную @NextCall для запроса). Цель этого - идентифицировать каждый раз, когда начнется новый вызов (EventID = 12). Если да, возьмите то, что есть в номере последовательности, и сохраните его. Это будет оставаться неизменным до следующего вызова, поэтому все остальные «идентификаторы событий» будут иметь одинаковый «идентификатор начальной последовательности». Кроме того, я ищу другие события ... событие = 22 на основе стартовой последовательности +1 и установки ее как флага. Затем максимальное время в зависимости от начала вызова (устанавливается только в случае eventid = 12) и завершения вызова (eventid = 30) и, наконец, флаг, основанный на вашей проверке для зависания (eventid = 13), т.е. : не рассматривайте вызов, если это зависание и никакого соединения.

Выполняя группу, я по существу свернул каждый вызов в свою линию, сгруппированный по идентификатору дома, и порядковый номер, используемый для инициирования фактического телефонного звонка. После того, как это будет сделано, я могу затем запросить данные и вычислить длительность вызова, так как время начала/окончания находится в одной и той же строке, при этом не включается самоизоляция.

Наконец, предложение where ... Вызвать любые телефонные звонки, которые были HANG UP.Опять же, я не знаю, нужен ли вам по-прежнему элемент того, что было временем стартового вызова последнего события окончания.

SELECT 
     PreGroupedCalls.*, 
     timediff(PreGroupedCalls.CallEndTime, PreGroupedCalls.CallStartTime) CallDuration 
    from 
     (SELECT 
       Calls.HomeID, 
       @NextCall := @NextCall + if(Calls.EventID = 12, Calls.Sequence, @NextCall) as NextNewCall, 
       MAX(if(Calls.EventID = 12, Calls.Stamp, 0)) as CallStartTime, 
       MAX(if(Calls.EventID = 30, Calls.Stamp, 0)) as CallEndTime, 
       MAX(if(Calls.EventID = 22 and Calls.Sequence = @NewCallFirstSeq +1, 1, 0)) as HadDTMFEntry, 
       MAX(if(Calls.EventID = 13 and Calls.Sequence = @NewCallFirstSeq +1, 1, 0)) as WasAHangUp 
      from 
       (select pe.HomeId, 
         pe.Sequence, 
         pe.EventID, 
         pe.Stamp 
        from 
         Phone_Events pe 
        where 
         pe.HomeID = 111 
        order by 
         pe.Sequence) Calls, 
       (select @NextCall := 0) SQLVars 
      group by 
       Calls.HomeID, 
       NextNewCall) PreGroupedCalls 

     LEFT JOIN Phone_Event PriorCallEvent 
      ON PreGroupCalls.NextNewCall = PriorCallEvent.Sequence -1 
    where 
     PreGroupedCalls.WasHangUp = 0 
     AND (PriorCallEvent.Sequence IS NULL 
     OR abs(timediff(PriorCallEvent.Stamp, PreGroupedCalls.CallStartTime)) > 10) 

КОММЕНТАРИЙ ОТ ОБРАТНОЙ СВЯЗИ/ОШИБКИ сообщил

Чтобы попытаться исправить двойной ошибки, вы, очевидно, нужно будет сделать небольшое изменение в SQLVARS выберите .. попробуйте следующее

(выберите @NextCall: = CAST (0 как INT)) SQLVars

Теперь, что делает IF() ... Давайте посмотрим.

@NextCall + если (Calls.EventID = 12, Calls.Sequence, @NextCall)

средства взглянуть на события с кодом. Если это 12 (то есть: снятие трубки), возьмите все номера последовательности для этой записи. Это станет новой «Start Sequence» другого вызова. Если нет, просто сохраняйте все, что было установлено последним значением, поскольку оно является продолжением текущего вызова. Теперь давайте посмотрим на некоторые смоделированных данных, чтобы помочь лучше проиллюстрировать все столбцы

Original data     Values that will ultimately be built into... 
HomeID Sequence EventID Stamp @NextCall 
111 1  12  8:00:00 1 beginning of a new call 
111 2  22  8:00:01 1 not a new "12" event, keep last value 
111 3  30  8:05:00 1 call ended, phone back on hook 
111 4  12  8:09:00 4 new call, use the sequence of THIS entry 
111 5  22  8:09:01 4 same call 
111 6  13  8:09:15 4 same call, but a hang up 
111 7  30  8:09:16 4 same call, phone back on hook 
111 8  12  8:15:30 8 new call, get sequence ID 
111 9  22  8:15:31 8 same call... 
111 10  30  8:37:15 8 same call ending... 

Now, the query SHOULD create something like this 
HomeID NextNewCall CallStartTime CallEndTime HadDTMFEntry WasAHangUp 
111  1    8:00:00  8:05:00  1    0 
111  4    8:09:00  8:09:16  1    1 
111  8    8:15:30  8:37:15  1    0 

Как вы можете видеть, @NextCall сохраняет все последовательные записи для данного вызова «сгруппированных» вместе, так что вы не должны просто используйте информацию больше, чем информацию о расстоянии или меньше ... Она всегда будет следовать определенному пути «событий», поэтому все, что запустило вызов, является основой для остальных событий, пока не будет запущен следующий вызов , то THAT-последовательность захватывается для группового вызова THAT.

Да, его много, чтобы понять .. но, надеюсь, теперь более удобоваримой для вас :)

+0

Хм .. Я добавил новый указатель и запустил вашу версию. Все еще ударил 10 минут таймаута. Сервер, о котором идет речь, представляет собой машину RHEL с пропускной способностью 8 кПа, 16 ГБ без другой нагрузки на нее (на данный момент). Похоже, это должно быть намного быстрее. – ethrbunny

+0

@ethrbunny, позвольте мне спросить вас об этом ... «HomeID» тоже автопризнан? Является ли это добавочным номером телефона? Временная шкала ... Есть ли ограничение по времени, которое вы ожидаете? Можете ли вы опубликовать НЕОБХОДИМЫЙ пример данных с вашим запросом? – DRapp

+0

@ethrbunny, Не могли бы вы перечислить различные идентификаторы событий и их соответствующие коды ... У меня есть идея, которая может работать ... Кроме того, у вас есть временная метка, но запрашивает весь файл ... Любое внимание к LIMIT определенный период времени ... например, за день, неделю, месяц? – DRapp

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