sql >> Databáze >  >> RDS >> Mysql

Proč je maximální časový limit MySQL 838:59:59?

TIME hodnoty byly v MySQL vždy uloženy na 3 bytech. Formát se však změnil ve verze 5.6 .4 . Tuším, že to nebylo poprvé, kdy se to změnilo. Ale ta druhá změna, pokud nějaká byla, se stala už dávno a neexistuje o ní žádný veřejný důkaz. Historie zdrojového kódu MySQL na GitHubu začíná verzí 5.5 (nejstarší commit je z května 2008), ale ke změně, kterou hledám, došlo někde kolem roku 2001-2002 (MySQL 4 byla spuštěna v roce 2003)

Aktuální formát, jak je popsán v dokumentaci, používá 6 bitů na sekundy (možné hodnoty:063 ), 6 bitů pro minuty, 10 bitů pro hodiny (možné hodnoty:0 na 1023 ), 1 bit pro znaménko (přičtěte záporné hodnoty již zmíněných intervalů) a 1 bit je nepoužitý a označený jako "rezervováno pro budoucí rozšíření".

Je optimalizován pro práci s časovými složkami (hodiny, minuty, sekundy) a nezabírá mnoho místa. Pomocí tohoto formátu je možné ukládat hodnoty mezi -1023:59:59 a +1023:59:59 . MySQL však omezuje počet hodin na 838 , pravděpodobně kvůli zpětné kompatibilitě s aplikacemi, které byly napsány před chvílí, kdy si myslím, že toto byl limit.

Do verze 5.6.4 TIME hodnoty byly také uloženy na 3 bytech a komponenty byly zabaleny jako days * 24 * 3600 + hours * 3600 + minutes * 60 + seconds . Tento formát byl optimalizován pro práci s časovými razítky (protože se ve skutečnosti jednalo o časové razítko). Pomocí tohoto formátu by bylo možné ukládat hodnoty v rozsahu přibližně -2330 na +2330 hodin. I když byl k dispozici tento velký rozsah hodnot, MySQL stále omezovalo hodnoty na -838 na +838 hodin.

Vyskytla se chyba č. 11655 na MySQL 4. Bylo možné vrátit TIME hodnoty mimo -838..+838 rozsah pomocí vnořeného SELECT prohlášení. Nebyla to funkce, ale chyba a byla opravena.

Jediný důvod k omezení hodnot na tento rozsah a k aktivní změně jakékoli části kódu, která vytváří TIME hodnoty mimo to byla zpětná kompatibilita.

Mám podezření, že MySQL 3 používal jiný formát, který kvůli způsobu sbalení dat omezil platné hodnoty na rozsah -838..+838 hodin.

Nahlédnutím do aktuálního zdrojového kódu MySQL Našel jsem tento zajímavý vzorec:

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

V tuto chvíli ignorujme MAX část jmen použitých výše a pamatujme si pouze to TIME_MAX_MINUTE a TIME_MAX_SECOND jsou čísla mezi 00 a 59 . Vzorec pouze zřetězí hodiny, minuty a sekundy do jediného celého čísla. Například hodnota 170:29:45 se změní na 1702945 .

Tento vzorec vyvolává následující otázku:vzhledem k tomu, že TIME hodnoty jsou uloženy na 3 bytech se znaménkem, jaká je maximální kladná hodnota, která může být tímto způsobem znázorněna?

Hodnota, kterou hledáme, je 0x7FFFFF že v desítkovém zápisu je 8388607 . Od posledních čtyř číslic (8607 ) je třeba číst jako minuty (86 ) a sekundy (07 ) a jejich maximální platné hodnoty jsou 59 , největší hodnota, kterou lze uložit na 3 bajty se znaménkem pomocí výše uvedeného vzorce, je 8385959 . Což jako TIME je +838:59:59 . Ta-da!

Hádej co? Fragment C kód uvedený výše byl extrahován z tohoto:

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

Jsem si jistý, že takhle MySQL 3 udržovala TIME hodnoty vnitřně. Tento formát ukládal omezení rozsahu a požadavek na zpětnou kompatibilitu u následujících verzí toto omezení rozšířil až do dnešních dnů.



  1. Seznam uložených funkcí, které odkazují na tabulku v PostgreSQL

  2. Chyba uložené procedury mysql (1172, 'Výsledek sestával z více než jednoho řádku')

  3. Pomalé řazení dotazů podle sloupce ve spojené tabulce

  4. Může řetězec kódovaný base64 obsahovat mezery?