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

Perché il limite di tempo massimo di MySQL è 838:59:59?

Il TIME i valori sono stati sempre memorizzati su 3 byte in MySQL. Ma il formato è cambiato su versione 5.6 .4 . Sospetto che questa non fosse la prima volta che cambiava. Ma l'altro cambiamento, se c'è stato, è avvenuto molto tempo fa e non ci sono prove pubbliche di ciò. La cronologia del codice sorgente di MySQL su GitHub inizia con la versione 5.5 (il commit più vecchio è di maggio 2008) ma il cambiamento che sto cercando è avvenuto da qualche parte intorno al 2001-2002 (MySQL 4 è ​​stato lanciato nel 2003)

Il formato attuale, come descritto nella documentazione, utilizza 6 bit per secondi (possibili valori:0 a 63 ), 6 bit per minuti, 10 bit per ore (valori possibili:0 a 1023 ), 1 bit per segno (aggiungere i valori negativi degli intervalli già citati) e 1 bit è inutilizzato ed etichettato come "riservato per future estensioni".

È ottimizzato per lavorare con componenti temporali (ore, minuti, secondi) e non spreca molto spazio. Utilizzando questo formato è possibile memorizzare valori compresi tra -1023:59:59 e +1023:59:59 . Tuttavia MySQL limita il numero di ore a 838 , probabilmente per compatibilità con le versioni precedenti con applicazioni che sono state scritte tempo fa, quando penso che questo fosse il limite.

Fino alla versione 5.6.4, il TIME anche i valori sono stati memorizzati su 3 byte e i componenti sono stati impacchettati come days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds . Questo formato è stato ottimizzato per lavorare con i timestamp (perché era, in effetti, un timestamp). Usando questo formato sarebbe possibile memorizzare valori nell'intervallo di circa -2330 a +2330 ore. Pur avendo a disposizione questa vasta gamma di valori, MySQL stava ancora limitando i valori a -838 a +838 ore.

C'era bug #11655 su MySQL 4. Era possibile restituire TIME valori al di fuori del -838..+838 intervallo utilizzando SELECT nidificato dichiarazioni. Non era una funzionalità ma un bug ed è stato corretto.

L'unico motivo per limitare i valori a questo intervallo e per modificare attivamente qualsiasi pezzo di codice che produce TIME valori al di fuori era la compatibilità con le versioni precedenti.

Sospetto che MySQL 3 abbia utilizzato un formato diverso che, a causa del modo in cui i dati sono stati compressi, ha limitato i valori validi all'intervallo -838..+838 ore.

Esaminando l'attuale codice sorgente di MySQL Ho trovato questa formula interessante:

#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)

Ignoriamo per il momento il MAX parte dei nomi usati sopra e ricordiamo solo che TIME_MAX_MINUTE e TIME_MAX_SECOND sono numeri compresi tra 00 e 59 . La formula concatena semplicemente ore, minuti e secondi in un unico numero intero. Ad esempio, il valore 170:29:45 diventa 1702945 .

Questa formula solleva la seguente domanda:dato che il TIME i valori sono memorizzati su 3 byte con segno, qual è il massimo valore positivo che può essere rappresentato in questo modo?

Il valore che stiamo cercando è 0x7FFFFF che in notazione decimale è 8388607 . Dalle ultime quattro cifre (8607 ) devono essere letti come minuti (86 ) e secondi (07 ) e il loro valore massimo valido è 59 , il valore massimo che può essere memorizzato su 3 byte con segno utilizzando la formula sopra è 8385959 . Quale, come TIME è +838:59:59 . Ta-da!

Indovina un po? Il frammento di C il codice sopra elencato è stato estratto da questo:

/* Limits for the TIME data type */
#define TIME_MAX_HOUR 838
#define TIME_MAX_MINUTE 59
#define TIME_MAX_SECOND 59
#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + TIME_MAX_SECOND)

Sono sicuro che questo è il modo in cui MySQL 3 ha utilizzato per mantenere il TIME valori internamente. Questo formato ha imposto la limitazione dell'intervallo e il requisito di compatibilità con le versioni precedenti ha propagato la limitazione ai nostri giorni.