Mysql
 sql >> Database >  >> RDS >> Mysql

Filtraggio del set di risultati della query MySQL per produrre più occorrenze entro un periodo di tempo specifico

Se vogliamo filtrare le righe in cui non ci sono almeno quattro righe precedenti negli ultimi 60 secondi, supponendo che dateTimeOrigination sia di tipo intero, un timestamp in stile unix a 32 bit, possiamo fare qualcosa del genere:

SELECT FROM_UNIXTIME(r.dateTimeOrigination) AS dateTimeOrigination
     , r.callingPartyNumber
     , r.originalCalledPartyNumber
     , r.finalCalledPartyNumber
     , r.duration
     , r.origDeviceName
     , r.destDeviceName
  FROM cdr_records r
 WHERE r.dateTimeOrigination >= UNIX_TIMESTAMP('2016-05-20')
   AND r.dateTimeOrigination  < UNIX_TIMESTAMP('2016-05-21')
   AND r.callingPartyNumber NOT LIKE 'b00%'
   AND r.originalCalledPartyNumber NOT LIKE 'b00%'
   AND r.finalCalledPartyNumber NOT LIKE 'b00%'

   AND ( SELECT COUNT(1)
           FROM cdr_records c
          WHERE c.originalCalledPartyNumber = r.originalCalledPartyNumber
            AND c.dateTimeOrigination       > r.dateTimeOrigination - 60
            AND c.dateTimeOrigination      <= r.dateTimeOrigination
       ) > 4

 ORDER
    BY r.originalCalledPartyNumber
     , r.dateTimeOrigination

NOTA:per le prestazioni, preferiamo avere predicati su colonne nude.

Con un form come questo, con la colonna racchiusa in un'espressione:

 WHERE FROM_UNIXTIME(r.dateTimeOrigination) LIKE '2016-05-20%'

MySQL valuterà la funzione per ogni riga nella tabella, quindi confrontare il valore restituito dalla funzione con il valore letterale.

Con un modulo come questo:

 WHERE r.dateTimeOrigination >= UNIX_TIMESTAMP('2016-05-20')
   AND r.dateTimeOrigination  < UNIX_TIMESTAMP('2016-05-21')

MySQL valuterà le espressioni sul lato destro uno tempo, come letterali . Ciò consente a MySQL di fare un uso efficace di un'operazione di scansione dell'intervallo su un indice adatto.

SEGUITO

Per le migliori prestazioni della query esterna, l'indice migliore sarebbe probabilmente un indice con la colonna iniziale di dateTimeOrigination, preferibilmente contenente

... ON cdr_records (dateTimeOrigination
    ,callingPartyNumber,originalCalledPartyNumber,finalCalledPartyNumber)

Per le migliori prestazioni, un indice di copertura, per evitare ricerche nelle pagine nella tabella sottostante. Ad esempio:

... ON cdr_records (dateTimeOrigination
    ,callingPartyNumber,originalCalledPartyNumber,finalCalledPartyNumber
    ,duration,origDeviceName,destDeviceName)

Con ciò, ci aspetteremmo che EXPLAIN mostri "Uso dell'indice".

Per la sottoquery correlata, vorremmo un indice con colonne iniziali come questa:

... ON cdr_records (originalCalledPartyNumber,dateTimeOrigination)

Consiglio vivamente di guardare l'output di EXPLAIN per vedere quali indici utilizza MySQL per la query.