حالة TIME الغامضة في MySQL

تقريبا. ترجمة. : تسبب هذا التحليل التفصيلي لأحد التفاصيل التي تبدو غير مهمة في التنفيذ داخل MySQL في مناقشات طبيعية حول مدى صحة الأساليب المتبعة في تطوير مشروع مفتوح المصدر معروف بشكل عام. ما اكتشفه المهندس البرتغالي في الواقع ، يروي بتنسيق قريب من قصة بوليسية ... وقع



العديد في عام 2020 ضحية لظاهرة غريبة تتعلق بإدراك الوقت ، لكن بعض أنظمة إدارة قواعد البيانات تتلاعب بالوقت لفترة أطول. لاحظت هذا لأول مرة عندماواجهصديق لي في أحد مشاريعه ( Accord هو برنامج Discord bot الشهير) الاستثناء التالي من موصل MySQL عند استخدامه مع EF Core:



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" لقيم الساعة الكبيرة).


حتى الآن، كل شيء على ما يرام: لدينا قيمة الوقت إشكالية يناسب بشكل جيد مع هذا الشكل، على الرغم من حقيقة أن hhما hhhيتم تحديده بشكل واضح يثير الشكوك (ماذا عن القيم مدار الساعة تتجاوز 999؟). تشرح الجملة التالية في التوثيق كل شيء جزئيًا ، مع تحفيز مجموعة من الأسئلة مثل "ما ...؟":



يمكن أن تتراوح قيم الوقت من "-838: 59: 59" إلى "838: 59: 59".


حسنًا ، حسنًا ... بعض النطاق الغريب. يجب أن يكون هناك سبب تقني جيد لذلك. 839 ساعة هي 34.958 (3) يومًا ، والنطاق الكامل هو 6040798 ثانية بالضبط. تقرأ الوثائق على النحو التالي:



يتعرف MySQL على قيم TIME بتنسيقات متعددة ، يمكن أن يتضمن بعضها أجزاء من الثواني تصل إلى 6 منازل عشرية (ميكروثانية).


بمعنى آخر ، الفاصل الزمني بأكمله هو 6،040،798،000،000 ميكروثانية. مرة أخرى ، رقم غريب. إنها أبعد ما تكون عن قوة اثنين (بين 2 42 و 2 43 ) ، لذلك يبدو أن MySQL تستخدم بعض تنسيقات التمثيل الداخلي الفريدة. لكن قبل أن أتطرق إلى هذه المشكلة ، دعني أوضح مدى سوء هذا النوع.



هذا هو كل ما تقدمه MySQL لقياس الفترات الزمنية ، مع امتداد الوقت بالكامل لما يزيد قليلاً عن شهر واحد. ما هو حجم هذا "قليلا"؟ كما ترى ، فهي ليست حتى من مضاعفات عدد صحيح من الأيام.



والأسوأ من ذلك ، أن MySQL الأكثر شهرة في موفر EF Core يحول .NET TimeSpanإلى TIME افتراضيًا ، على الرغم من حقيقة ذلكTimeSpanيمكن أن تحتوي على فترات من عشرات الآلاف من السنين (تستخدم الأعداد الصحيحة 64 بت ، والدقة المسموح بها هي 10 -8 ثوانٍ). قارن هذا بشهرين في TIME. واجه أشخاص آخرون



هذه المشكلة ، وتحتوي المناقشة في المشكلة المطابقة على مرجع لسلوك SQL Server: "هذا يحاكي سلوك SQL Server". لقد تحققت - بالفعل ، نوع وقت SQL Server له نطاق من 00: 00: 00.0000000 إلى 23: 59: 59.9999999 ، وهو بشكل عام أكثر منطقية من نطاق الوقت الغريب. لكن دعنا نعود إلى MySQL. ما هو سبب هذا النطاق غير العادي؟ في دليل جهاز MySQL



يقول أنه في الإصدار 5.6.4 ، تم تغيير نوع TIME وهناك دعم لكسور الثواني. يتم استخدام ثلاثة بايت للجزء بأكمله. إذا تم استخدام هذه البايت الثلاثة بالكامل لتشفير الثواني ، فإن هذا ينتج عنه فترة زمنية تزيد عن 2330 ساعة - أكثر بكثير من الحد الأقصى الحالي البالغ 838 ساعة (على الرغم من أن هذا ليس مفيدًا جدًا عند تحويل TimeSpan'أ).



هذا يعني أن العملية التي تقوم بترميز الوقت في MySQL تضيع بعض الأجزاء - ربما من أجل سهولة الاستخدام (على الرغم من أنني لست متأكدًا من أي ظروف يكون هذا مناسبًا) ربما يكون هذا منطقيًا إذا كان نظام إدارة قواعد البيانات (وفكرة المطورين لما سيفعله المستخدمون به) موجهًا نحو العمل مع السلاسل ، ويريد المطورون تسريع العرض التقديمي hh:mm:ss.



لذلك انظر:



1 — (1 = , 0 = )

1 ( )

10 — (0-838)

6 — (0-59)

6 — (0-59)

— 24 = 3


هذا يفسر كل شيء ، أليس كذلك؟ حسنًا ، دعنا نلقي نظرة فاحصة. 10 بت لساعات ... والمدى من صفر إلى 838. أسارع لتذكيرك بأن 2 10 = 1024 ، وليس 838. المؤامرة تكتسب زخمًا ...



بالطبع ، لست أول شخص طرح هذا السؤال (لقد سألت بالفعل عن هذا على StackOverflow ). يبدو أن كل شيء مذكور في الإجابة "المقبولة" هناك ، ومع ذلك ، فإن الاختيار الغريب لـ 838 ساعة تم شرحه أولاً من خلال "التوافق مع الإصدارات السابقة مع التطبيقات التي تمت كتابتها منذ وقت طويل جدًا" ، وعندها فقط يُذكر أن هذا له علاقة بالتوافق مع MySQL 3 - بالمناسبة ثم تم اعتبار Windows 98 حداثة ، ولم يكن عمر Linux حتى 10 سنوات.



في MySQL 3 ، استخدم نوع TIME أيضًا 3 بايت ، لكنه فعل ذلك بطريقة مختلفة تمامًا. تم حجز إحدى البتات أيضًا للعلامة ، لكن الـ 23 بت المتبقية تتوافق مع الأعداد الصحيحة التي تم الحصول عليها على النحو التالي: ساعات × 10000 + دقيقة × 100 + ثانية. بعبارة أخرى ، كان الرقمان الأقل دلالة هما الثواني ، والرقمان التاليان هما دقيقتان ، والباقيان هما ساعات. 2 * 23 هي 83888608 ، وهي 838: 86: 08 ، وبالتالي فإن الحد الأقصى لقيمة الوقت الصالحة في هذا التنسيق هو 838: 59: 59.



هذا التنسيق أقل ملاءمة من التنسيق الحالي ، لأنه يتطلب الضرب والقسمة تقريبًا في أي عملية زمنية (باستثناء تنسيق السلسلة والتحليل - مما يثبت مرة أخرى أن MySQL تولي اهتمامًا كبيرًا لسلسلة IO ولا تهتم حقًا بوجود الأنواع. والتي ستكون مناسبة للعمليات الداخلية والبروتوكولات غير القائمة على السلسلة).



تمكن مطورو MySQL من إصلاح هذا النوع عدة مرات ، أو على الأقل توفير بديل خالٍ من القيود الحالية. لقد تغير نوع TIME مرتين منذ MySQL 3 حتى اليوم ، ولكن في كل مرة ظل النطاق الغريب كما هو - ربما لأسباب تتعلق بالتوافق.



أنا في حيرة من أمري لتخيل موقف قد يؤدي فيه توسيع نطاق قيمة لنوع ما إلى تعطيل توافق التطبيقات: هل تمتلك الأنواع في MySQL سلوك تجاوز معين؟ أي مبرمج عاقل سيعتمد على القيود الداخلية لأنواع قاعدة البيانات للتحقق من صحة شيء ما في تطبيقهم؟ إذا كان هناك مثل هذا الشخص ، فلماذا يقرر فجأة نقل هذا الحد السخيف البالغ 838 ساعة إلى نموذج البيانات الخاص بتطبيقه دون أي تغييرات؟ لأكون صادقًا ، لا أريد حتى معرفة إجابات هذه الأسئلة.



على الرغم من حدوث بعض التحولات الرئيسية في تاريخ MySQL ، إلا أن نوع TIME لا يزال محرجًا ومحدودًا. وأبرز ما يميز البرنامج هنا ، في رأيي ، هو الجزء غير المستخدم "المخصص للإضافات المستقبلية". آمل أن تشير في المستقبل إلى قيمة الوقت القديمة القديمة ، وبحلول ذلك الوقت سيكون لدى MySQL و / أو MariaDB نوع زمني معقول ، مثل INTERVAL في PostgreSQL ، والذي يمتد إلى 178.000.000 سنة ومايكروثانية صحة.



PS من المترجم



اقرأ أيضًا على مدونتنا:






All Articles