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

Longitud DECIMAL para microtiempo (verdadero)?

tl; dr. Use microtime (falso) y almacene los resultados en un bigint de MySQL como millonésimas de segundo. De lo contrario, debe aprender todo sobre la aritmética de punto flotante, que es una bola de pelo grande y gorda.

La función de microtiempo de PHP toma la marca de tiempo de Unix (actualmente alrededor de 50eb7c00 hexadecimal o decimal 1,357,609,984) de una llamada al sistema y el tiempo en microsegundos de otra llamada al sistema. Luego los convierte en una cadena de caracteres. Luego, si lo llama con (verdadero), convierte ese número en un número de punto flotante IEEE 745 de 64 bits, algo que PHP llama un float .

A partir de hoy, necesita diez dígitos decimales a la izquierda del punto decimal para almacenar una marca de tiempo UNIX entera. Eso seguirá siendo cierto hasta alrededor de 2280 CE, cuando sus descendientes comenzarán a necesitar once dígitos. Necesitará seis dígitos a la derecha del lugar decimal para almacenar los microsegundos.

No obtendrá una precisión total de microsegundos. La mayoría de los sistemas mantienen su reloj de sistema de subsegundos con una resolución de algo en el rango de 1-33 milisegundos. Depende del sistema.

MySQL versión 5.6.4 y posteriores le permiten especificar DATETIME(6) columnas, que contendrán fechas y horas con una resolución de microsegundos. Si está utilizando una versión de MySQL de este tipo, ese es absolutamente el camino a seguir.

Antes de la versión 5.6.4, debe usar MySQL DOUBLE (IEEE 754 de punto flotante de 64 bits) para almacenar estos números. MySQL FLOAT (IEEE 754 de punto flotante de 32 bits) no tiene suficientes bits en su mantisa para almacenar incluso el tiempo UNIX actual en segundos con total precisión.

¿Por qué estás almacenando estas marcas de tiempo? ¿Esperas hacer

  WHERE table.timestamp = 1357609984.100000

o consultas similares para buscar elementos particulares? Eso está lleno de peligros si usa números flotantes o dobles en cualquier parte de su cadena de procesamiento (es decir, incluso si usa microtime(true) incluso una vez). Son conocidos por no ser iguales incluso cuando pensabas que deberían. En su lugar, necesita usar algo como esto. El 0.001 Se llama "épsilon" en el comercio de procesamiento numérico.

  WHERE table.timestamp BETWEEN 1357609984.100000 - 0.001
                            AND 1357609984.100000 + 0.001

o algo similar. No tendrá este problema si almacena estas marcas de tiempo como decimales o en millonésimas de segundo en un bigint columna.

El punto flotante IEEE de 64 bits tiene 53 bits de mantisa, de precisión. La marca de tiempo actual de UNIX Epoch (segundos desde el 1 de enero de 1970 a las 00:00 Z) multiplicada por un millón utiliza 51 bits. Por lo tanto, no hay mucha precisión adicional en el DOBLE si nos preocupamos por el bit de orden inferior. Por otro lado, la precisión no se agotará hasta dentro de un par de siglos.

No está cerca de quedarse sin precisión con int64 (BIGINT). Si en realidad estuviera almacenando marcas de tiempo de microsegundos solo para ordenarlas en MySQL, iría con DATETIME(6) porque obtendría mucha aritmética de fechas gratis. Si estuviera haciendo una aplicación de alto volumen en memoria, usaría int64.