sql >> Databasteknik >  >> RDS >> Mysql

Varför är MySQL:s maximala tidsgräns 838:59:59?

TIME värden lagrades alltid på 3 byte i MySQL. Men formatet ändrades på version 5.6 .4 . Jag misstänker att det inte var första gången det ändrades. Men den andra förändringen, om det fanns en, skedde för länge sedan och det finns inga offentliga bevis för det. MySQL-källkodshistoriken på GitHub börjar med version 5.5 (den äldsta commit är från maj 2008) men ändringen jag letar efter skedde någonstans runt 2001-2002 (MySQL 4 lanserades 2003)

Det aktuella formatet, som beskrivs i dokumentationen, använder 6 bitar i sekunder (möjliga värden:0 till 63 ), 6 bitar för minuter, 10 bitar för timmar (möjliga värden:0 till 1023 ), 1 bit för tecken (lägg till de negativa värdena för de redan nämnda intervallen) och 1 bit är oanvänd och märkt "reserverad för framtida tillägg".

Den är optimerad för att arbeta med tidskomponenter (timmar, minuter, sekunder) och slösar inte mycket utrymme. Med detta format är det möjligt att lagra värden mellan -1023:59:59 och +1023:59:59 . MySQL begränsar dock antalet timmar till 838 , förmodligen för bakåtkompatibilitet med applikationer som skrevs för ett tag sedan, när jag tror att detta var gränsen.

Fram till version 5.6.4, TIME värden lagrades också på 3 byte och komponenterna packades som days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds . Detta format var optimerat för att arbeta med tidsstämplar (eftersom det i själva verket var en tidsstämpel). Med detta format skulle det vara möjligt att lagra värden i intervallet ungefär -2330 till +2330 timmar. Även om MySQL hade det här stora utbudet av värden tillgängligt begränsade fortfarande värdena till -838 till +838 timmar.

Det fanns bugg #11655 på MySQL 4. Det var möjligt att returnera TIME värden utanför -838..+838 intervall med kapslad SELECT uttalanden. Det var inte en funktion utan en bugg och det fixades.

Det enda skälet att begränsa värdena till det här intervallet och att aktivt ändra alla stycken kod som producerar TIME värden utanför det var bakåtkompatibilitet.

Jag misstänker att MySQL 3 använde ett annat format som, på grund av hur data packades, begränsade de giltiga värdena till intervallet -838..+838 timmar.

Genom att titta på den nuvarande MySQL:s källkod Jag hittade denna intressanta formel:

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

Låt oss för tillfället ignorera MAX en del av namnen som används ovan och låt oss bara komma ihåg den TIME_MAX_MINUTE och TIME_MAX_SECOND är siffror mellan 00 och 59 . Formeln sammanfogar bara timmarna, minuterna och sekunderna i ett enda heltal. Till exempel värdet 170:29:45 blir 1702945 .

Denna formel väcker följande fråga:givet att TIME värden lagras på 3 byte med tecken, vilket är det maximala positiva värdet som kan representeras på detta sätt?

Värdet vi letar efter är 0x7FFFFF som i decimalnotation är 8388607 . Sedan de fyra sista siffrorna (8607 ) ska läsas som minuter (86 ) och sekunder (07 ) och deras maximala giltiga värden är 59 , det största värdet som kan lagras på 3 byte med tecken med formeln ovan är 8385959 . Vilket som TIME är +838:59:59 . Ta-da!

Gissa vad? Fragmentet av C koden som anges ovan extraherades från detta:

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

Jag är säker på att det är så MySQL 3 brukade hålla TIME värden internt. Detta format införde begränsningen av intervallet, och kravet på bakåtkompatibilitet på de efterföljande versionerna spred begränsningen till våra dagar.



  1. internationaliserat reguljärt uttryck i postgresql

  2. Hur söker man efter Soundex()-substrängar i MySQL?

  3. Transformational Stories på MariaDB OpenWorks Conference

  4. Lär dig mer om MySQL-tabellnivåbehörigheter