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

Hvorfor er MySQL's maksimale tidsgrænse 838:59:59?

TIME værdier blev altid gemt på 3 bytes i MySQL. Men formatet ændrede sig på version 5.6 .4 . Jeg formoder, at det ikke var første gang, det ændrede sig. Men den anden ændring, hvis der var en, skete for længe siden, og der er ingen offentlige beviser for det. MySQL-kildekodehistorikken på GitHub starter med version 5.5 (den ældste commit er fra maj 2008), men den ændring, jeg leder efter, skete et sted omkring 2001-2002 (MySQL 4 blev lanceret i 2003)

Det aktuelle format, som beskrevet i dokumentationen, bruger 6 bits i sekunder (mulige værdier:0 til 63 ), 6 bit i minutter, 10 bit i timer (mulige værdier:0 til 1023 ), 1 bit for fortegn (tilføj de negative værdier af de allerede nævnte intervaller) og 1 bit er ubrugt og mærket "reserveret til fremtidige udvidelser".

Den er optimeret til at arbejde med tidskomponenter (timer, minutter, sekunder) og spilder ikke meget plads. Ved at bruge dette format er det muligt at gemme værdier mellem -1023:59:59 og +1023:59:59 . Men MySQL begrænser antallet af timer til 838 , sandsynligvis for bagudkompatibilitet med programmer, der blev skrevet for et stykke tid siden, da jeg tror, ​​at dette var grænsen.

Indtil version 5.6.4 er TIME værdier blev også gemt på 3 bytes, og komponenterne blev pakket som days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds . Dette format var optimeret til at arbejde med tidsstempler (fordi det i virkeligheden var et tidsstempel). Ved at bruge dette format ville det være muligt at gemme værdier i området omkring -2330 til +2330 timer. Mens MySQL havde denne store række af værdier til rådighed, begrænsede MySQL stadig værdierne til -838 til +838 timer.

Der var fejl #11655 på MySQL 4. Det var muligt at returnere TIME værdier uden for -838..+838 område ved hjælp af indlejret SELECT udsagn. Det var ikke en funktion, men en fejl, og det blev rettet.

Den eneste grund til at begrænse værdierne til dette område og aktivt ændre ethvert kodestykke, der producerer TIME værdier uden for det var bagudkompatibilitet.

Jeg formoder, at MySQL 3 brugte et andet format, der på grund af den måde, dataene blev pakket på, begrænsede de gyldige værdier til området -838..+838 timer.

Ved at se på den aktuelle MySQL's kildekode Jeg fandt denne interessante formel:

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

Lad os for øjeblikket ignorere MAX del af navnene, der er brugt ovenfor, og lad os kun huske den TIME_MAX_MINUTE og TIME_MAX_SECOND er tal mellem 00 og 59 . Formlen sammenkæder bare timer, minutter og sekunder i et enkelt heltal. For eksempel værdien 170:29:45 bliver 1702945 .

Denne formel rejser følgende spørgsmål:givet at TIME værdier er gemt på 3 bytes med fortegn, hvad er den maksimale positive værdi, der kan repræsenteres på denne måde?

Værdien vi leder efter er 0x7FFFFF der i decimalnotation er 8388607 . Siden de sidste fire cifre (8607 ) skal læses som minutter (86 ) og sekunder (07 ) og deres maksimale gyldige værdier er 59 , den største værdi, der kan gemmes på 3 bytes med fortegn ved hjælp af formlen ovenfor, er 8385959 . Hvilket, som TIME er +838:59:59 . Ta-da!

Gæt hvad? Fragmentet af C kode anført ovenfor blev udtrukket fra denne:

/* 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)

Jeg er sikker på, at det er sådan MySQL 3 plejede at holde TIME værdier internt. Dette format pålagde begrænsningen af ​​rækkevidden, og kravet om bagudkompatibilitet på de efterfølgende versioner udbredte begrænsningen til vore dage.



  1. Sådan bruger du goto label i MySQL-lagret funktion

  2. COUNT(*) returnerer flere rækker i stedet for kun én

  3. Blokerer '0000-00-00' fra MySQL-datofelter

  4. GROUP_CONCAT tilsvarende i Django