2015-05-12 12 views
5

Ho questa tabella che rappresenta i pacchetti da una cattura di traffico chiamato PacketsByDirection (che mostrano solo i campi rilevanti):Calcolare differenza tra 2 volte d'epoca, grande tavolo, ottimizzare avendo 3 indici

FrameNumber FrameTimeEpoch   FlowID Direction 
    288  1430221042.150789000  29  Direction A 
    289  1430221042.150922000  29  Direction B 

Ora, questo tavolo ha circa 2 milioni di righe (pacchetti) e quello che ho bisogno di calcolare è, per ogni pacchetto, la differenza di tempo tra lui e il pacchetto precedente con lo stesso senso e la stessa FlowID

ho fatto con questa query, oltre ad aggiungere indici alla tabella precedente per rendere la query più veloce.

SELECT t1.FrameNumber, flowid, direction, 
    FrameTimeEpoch - IFNULL((
         SELECT MAX(FrameTimeEpoch) 
         FROM PacketsByDirection 
         WHERE flowid = t1.flowid 
         AND Direction LIKE t1.Direction 
         AND FrameNumber < t1.FrameNumber) 
        ,FrameTimeEpoch) AS TimeFromLastPacketFromSameDirection 
FROM PacketsByDirection AS t1 

E il risultato è qualcosa di simile

FrameNumber  FlowID Direction TimeFromLastPacketFromSameDirection 
     288   29  Direction A     0 
     289   29  Direction B     0 
     290   29  Direction A     5.422 
     291   29  Direction B     4.356 
     292   30  Direction A     0 
     293   30  Direction A     1.302 

E così via. Ora, questa query richiede circa 1 ora per 600k righe, e ora sto lavorando con milioni di righe quindi non voglio nemmeno provarlo. Ecco l'uscita "spiegare" della query in questo momento (che è un sacco di iterazioni):

enter image description here

Quindi la mia domanda è: esiste un altro modo più efficace per fare questo?

Grazie

EDIT: Ecco la definizione della tabella

CREATE TABLE `packetsbydirection` (
    `FrameNumber` int(11) NOT NULL DEFAULT '0', 
    `FrameTimeEpoch` varchar(45) NOT NULL, 
    `IPSrc` varchar(45) NOT NULL, 
    `TCPSrcPort` varchar(45) DEFAULT NULL, 
    `UDPSrcport` varchar(45) DEFAULT NULL, 
    `IPDst` varchar(45) NOT NULL, 
    `TCPDstport` varchar(45) DEFAULT NULL, 
    `UDPDstport` varchar(45) DEFAULT NULL, 
    `IPLength` varchar(45) NOT NULL, 
    `FlowID` int(11) NOT NULL, 
    `Direction` varchar(11) CHARACTER SET utf8 DEFAULT NULL, 
    KEY `Index2` (`Direction`), 
    KEY `Index3` (`FlowID`), 
    KEY `Index4` (`FrameNumber`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
+0

Una bella domanda! Per favore includi l'intera definizione del tuo tavolo. Per le query al volume di righe che descrivi, non ci sono colonne irrilevanti o indici. –

+0

Certo, l'ho aggiunto al post – luistox

+0

Perché stai facendo un 'LIKE' per far corrispondere' Direzione '? Sicuramente devono essere esattamente lo stesso valore, quindi equals (=) sarebbe più appropriato - 'LIKE' _might_ non danneggia le prestazioni, ma' = 'è semanticamente migliore. – Raad

risposta

3
Non

sicuro se questo potrebbe funzionare a tutti, ma i numeri forse in esecuzione potrebbe essere più veloce?

SELECT 
     FrameNumber, 
     case when FlowID <> @currflow or Direction <> @currdir then @diff := 0 else @diff := FrameTimeEpoch - @epoch end as TimeFromLastPacketFromSameDirection 
     , @currflow := FlowID, @currdir := Direction, @diff, @epoch := FrameTimeEpoch 
    FROM 
     packetsbydirection, (select @epoch := 0, @currflow :="", @currdir := "", @diff := 0) as tmp 
    ORDER BY FlowID, Direction, FrameTimeEpoch 
+0

@luistox: funziona? Sono molto curioso di sapere – blubear

+0

Lo stavo provando! Lo fa! E davvero veloce, meno di 20 secondi. Stavo cercando di capire la query ... non sapevo che avrei potuto farlo in Mysql. Grazie mille, hai salvato la mia giornata! – luistox

+0

Fantastico, felice che funzioni per te. Fare aggregazione su ogni riga è costoso e dovrebbe essere evitato quando si lavora con un set di dati di grandi dimensioni. – blubear

Problemi correlati