MySQLの不思議な時間の状況

約transl。:MySQL内の実装における一見取るに足らない詳細のこの詳細な分析は、一般的に有名なオープンソースプロジェクトの開発へのアプローチの正しさについての正当な議論引き起こしました。ポルトガルのエンジニアが実際に見つけたものは、探偵小説に近い形式で語っています...



2020年に多くの人が時間知覚の奇妙な現象の犠牲になりましたが、一部のデータベース管理システムははるかに長い時間操作します。私の友人が彼のプロジェクトの1つAccordは人気のあるDiscordボットです)でEF Coreと一緒に使用すると、MySQLコネクタから次の例外が発生したときに最初に気づきました



MySqlException: Incorrect TIME value: '960:00:00.000000'


MySQLに精通しているわけではありませんが(すぐに明らかになる理由でPostgreSQLを好むので)、時間数が間違っていると一瞬思いました。TIME値が24時間に制限されている、または複数日にわたる値には異なる構文が必要であると想定するのが妥当40:00:00:00です。たとえば、40日を表します。しかし、現実ははるかに複雑で混乱していることが判明しました。



次の明らかなステップは、MySQLのドキュメントを確認することでしたそれは読んだ:



MySQLは、TIME値を「hh:mm:ss」形式(または大きな時間値の場合は「hhh:mm:ss」形式)で受信して表示します。


これまでのところ、すべてが正常です:問題のあるTIME値はこの形式にうまく適合しますが、hhそれらhhhが明示的に指定されいるという事実は疑わしいものです(999を超えるクロック値はどうですか?)。ドキュメントの次の文は、「What the ...?」のような一連の質問を刺激する過程で、すべてを部分的に説明しています。



TIME値の範囲は「-838:59:59」から「838:59:59」です。


大丈夫...いくつかの奇妙な範囲。これには技術的な理由があるはずです。839時間は34.958(3)日で、範囲全体は正確に6040798秒です。ドキュメントは次のようになっています。



MySQLは、いくつかの形式でTIME値を認識します。その中には、小数点以下6桁(マイクロ秒)までの小数秒を含めることができるものもあります。


つまり、間隔全体は6,040,798,000,000マイクロ秒です。繰り返しますが、いくつかの奇妙な数。それははるかに(2の間の2のべき乗である42 2 43)ので、MySQLはいくつかのユニークな内部表現の形式を使用しているように見えます。しかし、この問題に入る前に、このタイプがどれほど悪いかを指摘させてください。



これがMySQLが時間間隔を測定するために提供しなければならないすべてであり、全体の期間は1か月強です。この「少し」の大きさはどれくらいですか?ご覧のとおり、それは整数日の倍数ではありません。



さらに悪いことに、最も人気のあるMySQL to EF Coreプロバイダーは、デフォルトTimeSpan.NETをTIMEに変換します。TimeSpan数千年の間隔を含めることができます(64ビットの整数を使用し、許容される精度は10 -8秒です)。これをTIMEの数か月と比較してください。他の人が



この問題遭遇しました。対応する問題の説明には、SQLServerの動作への参照が含まれています:「これはSQLServerの動作を模倣しています」。私が確認しました-実際、SQL Serverの時間タイプ範囲は00:00:00.0000000から23:59:59.9999999であり、これは通常、奇妙なTIME範囲よりもはるかに合理的です。



しかし、MySQLに戻りましょう。そのような異常な範囲の理由は何ですか?ではMySQLのデバイスのマニュアルバージョン5.6.4では、TIMEタイプが変更され、数分の1秒がサポートされていると述べています。全体で3バイト使用しています。これらの3バイトが完全に秒のエンコードに使用される場合、2,330時間以上の期間になります。これは、現在の最大値である838時間よりもはるかに長くなります(ただし、TimeSpan'aを変換する場合はあまり役に立ちません)。



これは、MySQLで時間をエンコードするプロセスが、おそらく使いやすさのためにビットを浪費していることを意味します(ただし、これがどのような状況で関連するかはわかりません)。 DBMS(およびユーザーがDBMSで何をするかについての開発者の考え)が文字列の操作に向けられており、開発者がプレゼンテーションを高速化したい場合、これはおそらく理にかなっていますhh:mm:ss



だから参照してください:



1 — (1 = , 0 = )

1 ( )

10 — (0-838)

6 — (0-59)

6 — (0-59)

— 24 = 3


それがすべてを説明しますね。さて、詳しく見てみましょう。 10時間のビット...と範囲が2ということを思い出させるために、ゼロから838のI早めるためである10 = 1024、陰謀が勢いを増していない838 ...



もちろん、私はこの質問をした最初の人(私は既に持ってないんだけど頼まこれについてStackOverflowの上で)。そこの「受け入れられた」答えにはすべて述べられているようですが、838時間という奇妙な選択は、最初に「かなり昔に書かれたアプリケーションとの後方互換性」によって説明され、その後、これはMySQL3との互換性と関係があると述べられています-ちなみにその後、Windows 98は目新しいものと見なされ、Linuxは10年も経っていませんでした。



MySQL 3では、TIMEタイプも3バイトを使用しましたが、まったく異なる方法で使用していました。ビットの1つも符号用に予約されていましたが、残りの23ビットは、時間×10,000 +分×100 +秒のように取得された整数に対応していました。つまり、最下位2桁は秒、次の2桁は分、残りの2桁は時間でした。 2 * 23は83888608、つまり838:86:08であるため、この形式の最大有効時間値は838:59:59です。



このフォーマットは、ほとんどすべての時間の操作で乗算と除算が必要になるため、現在のフォーマットよりもさらに便利ではありません(文字列のフォーマットと解析を除く-これも、MySQLが文字列IOに過度の注意を払い、型の存在をあまり気にしないことを証明しています。これは、内部操作や非文字列ベースのプロトコルに便利です)。



MySQL開発者は、このタイプを何度も修正するか、少なくとも既存の制限のない代替タイプを提供することができました。 TIMEタイプはMySQL3から今日まで2回変更されましたが、そのたびに奇妙な範囲は同じままです-おそらく互換性の理由からです。



型の値の範囲を拡張するとアプリケーションの互換性が損なわれる可能性がある状況を想像するのに迷っています。MySQLの型には特定のオーバーフロー動作がありますか?アプリケーションで何かを検証するために、どの正気のプログラマーが内部データベースタイプの制約に依存するでしょうか?そのような人がいるとしたら、なぜ彼はこのばかげた838時間の制限を、変更を加えずにアプリケーションのデータモデルに突然転送することにしたのでしょうか。正直なところ、私はこれらの質問に対する答えを知りたくありません。



MySQLの歴史にはいくつかの大きな変化がありましたが、TIMEタイプは依然として扱いにくく制限されています。そして、ここでのプログラムのハイライトは、私の意見では、「将来の拡張のために予約されている」未使用のビットです。長期的には、古いレガシーTIME値を指し、それまでにMySQLやMariaDBが、±178、000、000年、マイクロ秒の範囲で、PostgreSQLのINTERVALなどの適切な時間タイプになることを願っています。正確さ。



翻訳者からのPS



私たちのブログも読んでください:






All Articles