sql >> Base de Datos >  >> RDS >> Mysql

Filtrado del conjunto de resultados de consultas de MySQL para generar múltiples ocurrencias dentro de un período de tiempo específico

Si queremos filtrar las filas donde no hay al menos cuatro filas anteriores en los últimos 60 segundos, suponiendo que dateTimeOrigination es de tipo entero, una marca de tiempo estilo Unix de 32 bits, podemos hacer algo como esto:

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:Por motivos de rendimiento, preferimos tener predicados en columnas vacías.

Con un formulario como este, con la columna envuelta en una expresión:

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

MySQL evaluará la función para cada fila en la tabla y luego compare el retorno de la función con el literal.

Con un formulario como este:

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

MySQL evaluará las expresiones del lado derecho one tiempo, como literales . Lo que permite a MySQL hacer un uso efectivo de una operación de escaneo de rango en un índice adecuado.

SEGUIMIENTO

Para obtener el mejor rendimiento de la consulta externa, el mejor índice probablemente sea un índice con la columna inicial de dateTimeOrigination, preferiblemente que contenga

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

Para un mejor rendimiento, un índice de cobertura, para evitar búsquedas en las páginas de la tabla subyacente. Por ejemplo:

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

Con eso, esperaríamos que EXPLAIN mostrara "Usando el índice".

Para la subconsulta correlacionada, nos gustaría un índice con columnas iniciales como esta:

... ON cdr_records (originalCalledPartyNumber,dateTimeOrigination)

Le recomiendo encarecidamente que mire el resultado de EXPLAIN para ver qué índices usa MySQL para la consulta.