لماذا تحتاج إلى دعم فعال لترقيم الصفحات على المفاتيح؟

أهلاً بكم! أنا مطور الواجهة الخلفية وأكتب الخدمات الصغيرة في Java + Spring. أعمل في أحد فرق تطوير المنتجات الداخلية في Tinkoff.

لماذا تحتاج إلى دعم فعال لترقيم الصفحات على المفاتيح؟

غالبًا ما يطرح فريقنا مسألة تحسين الاستعلامات في نظام إدارة قواعد البيانات. تريد دائمًا أن تكون أسرع قليلًا، لكن لا يمكنك دائمًا التعامل مع الفهارس التي تم إنشاؤها بعناية — عليك أن تبحث عن بعض الحلول. خلال إحدى هذه الرحلات عبر الويب بحثًا عن تحسينات معقولة عند العمل مع قواعد البيانات، وجدت مدونة ماركوس ويناند المفيدة التي لا نهاية لها، مؤلف كتاب شرح أداء SQL. هذا هو النوع النادر من المدونات الذي يمكنك من خلاله قراءة جميع المقالات المتتالية.

أود أن أترجم لك مقالة قصيرة كتبها ماركوس. يمكن أن يطلق عليه إلى حد ما بيانًا يسعى إلى لفت الانتباه إلى المشكلة القديمة، ولكن لا تزال ذات صلة، المتعلقة بأداء عملية الإزاحة وفقًا لمعيار SQL.

في بعض الأماكن سأكمل المؤلف بالتفسيرات والتعليقات. سأشير إلى جميع هذه الأماكن باسم "تقريبًا". لمزيد من الوضوح

مقدمة صغيرة

أعتقد أن الكثير من الأشخاص يعرفون مدى صعوبة وبطء العمل مع تحديد الصفحة عبر الإزاحة. هل تعلم أنه يمكن استبداله بسهولة بتصميم أكثر كفاءة؟

لذا، فإن الكلمة الأساسية offset تخبر قاعدة البيانات بتخطي السجلات n الأولى في الطلب. ومع ذلك، لا تزال قاعدة البيانات بحاجة إلى قراءة سجلات n الأولى من القرص، بالترتيب المحدد (ملاحظة: تطبيق الفرز إذا تم تحديده)، وعندها فقط سيكون من الممكن إرجاع السجلات من n+1 فصاعدًا. الشيء الأكثر إثارة للاهتمام هو أن المشكلة ليست في التنفيذ المحدد في نظام إدارة قواعد البيانات، ولكن في التعريف الأصلي وفقًا للمعيار:

...يتم فرز الصفوف أولاً وفقًا لـ ثم يقتصر ذلك على إسقاط عدد الصفوف المحددة في الملف من البداية…
-SQL:2016، الجزء 2، 4.15.3 الجداول المشتقة (ملاحظة: المعيار الأكثر استخدامًا حاليًا)

النقطة الأساسية هنا هي أن الإزاحة تأخذ معلمة واحدة - عدد السجلات المراد تخطيها، وهذا كل شيء. باتباع هذا التعريف، يمكن لنظام إدارة قواعد البيانات (DBMS) استرداد جميع السجلات فقط ثم التخلص من السجلات غير الضرورية. من الواضح أن هذا التعريف للإزاحة يجبرنا على القيام بعمل إضافي. ولا يهم حتى ما إذا كان SQL أو NoSQL.

فقط المزيد من الألم

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

لماذا تحتاج إلى دعم فعال لترقيم الصفحات على المفاتيح؟

عند استخدام الإزاحة لتخطي السجلات من الصفحات السابقة، في حالة إضافة سجل جديد بين قراءات الصفحات المختلفة، فمن المرجح أن تحصل على نسخ مكررة (ملاحظة: هذا ممكن عندما نقرأ صفحة تلو الأخرى باستخدام الترتيب حسب البناء، ثم في منتصف مخرجاتنا قد يحصل على إدخال جديد).

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

كما اكتشفنا بالفعل، هذه ليست مشاكل تتعلق بنظام إدارة قواعد بيانات معين أو تطبيقاته. تكمن المشكلة في تحديد ترقيم الصفحات وفقًا لمعيار SQL. نخبر نظام إدارة قواعد البيانات (DBMS) بالصفحة التي يجب جلبها أو عدد السجلات التي يجب تخطيها. قاعدة البيانات ببساطة غير قادرة على تحسين مثل هذا الطلب، حيث أن المعلومات المتوفرة لهذا قليلة جدًا.

ومن الجدير أيضًا توضيح أن هذه ليست مشكلة في كلمة رئيسية معينة، بل في دلالات الاستعلام. هناك العديد من تركيبات الجملة المتطابقة في طبيعتها الإشكالية:

  • الكلمة الأساسية الإزاحة هي كما ذكرنا سابقًا.
  • بناء حد من كلمتين رئيسيتين [إزاحة] (على الرغم من أن الحد في حد ذاته ليس سيئًا للغاية).
  • التصفية حسب الحدود الدنيا، استنادًا إلى ترقيم الصفوف (على سبيل المثال،row_number() وrownum وما إلى ذلك).

كل هذه التعبيرات تخبرك ببساطة بعدد الأسطر التي يجب تخطيها، دون أي معلومات أو سياق إضافي.

لاحقًا في هذه المقالة، سيتم استخدام الكلمة الأساسية offset كملخص لكل هذه الخيارات.

الحياة بدون إزاحة

والآن دعونا نتخيل كيف سيكون عالمنا بدون كل هذه المشاكل. اتضح أن الحياة بدون إزاحة ليست صعبة للغاية: مع التحديد، يمكنك تحديد فقط تلك الصفوف التي لم نرها بعد (ملاحظة: أي تلك التي لم تكن موجودة في الصفحة السابقة)، باستخدام شرط حيث.

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

    SELECT ...
    FROM ...
    WHERE ...
    AND id < ?last_seen_id
    ORDER BY id DESC
    FETCH FIRST 10 ROWS ONLY

هذا هو المبدأ الكامل لهذا النهج. وبطبيعة الحال، تصبح الأمور أكثر متعة عند الفرز حسب العديد من الأعمدة، ولكن الفكرة لا تزال هي نفسها. من المهم أن نلاحظ أن هذا التصميم ينطبق على الكثيرين NoSQL-قرارات.

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

إحدى الشرائح يتحدث عن ذلكوبطبيعة الحال، فإن ترقيم الصفحات حسب المفاتيح ليس له القدرة المطلقة - بل له حدوده. الأهم أنها لا تملك القدرة على قراءة الصفحات العشوائية (ملاحظة: بشكل غير متناسق). ومع ذلك، في عصر التمرير الذي لا نهاية له (ملاحظة: في الواجهة الأمامية)، هذه ليست مشكلة. يعد تحديد رقم الصفحة للنقر قرارًا سيئًا في تصميم واجهة المستخدم على أي حال (ملاحظة: رأي كاتب المقال).

ماذا عن الأدوات؟

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

يتفاقم الوضع بسبب حقيقة أن الطريقة الموضحة تتطلب دعمًا شاملاً في التقنيات المستخدمة - من نظام إدارة قواعد البيانات (DBMS) إلى تنفيذ طلب AJAX في المتصفح مع التمرير اللانهائي. بدلاً من تحديد رقم الصفحة فقط، عليك الآن تحديد مجموعة من المفاتيح لجميع الصفحات مرة واحدة.

ومع ذلك، فإن عدد الأطر التي تدعم ترقيم الصفحات على المفاتيح يتزايد تدريجياً. إليك ما لدينا في الوقت الحالي:

(ملاحظة: تمت إزالة بعض الروابط لأنه في وقت الترجمة لم يتم تحديث بعض المكتبات منذ 2017-2018. إذا كنت مهتمًا، يمكنك إلقاء نظرة على المصدر الأصلي.)

في هذه اللحظة هناك حاجة لمساعدتكم. إذا قمت بتطوير أو دعم إطار عمل يستخدم ترقيم الصفحات، فأنا أطلب منك، وأحثك، وأطلب منك تقديم دعم أصلي لترقيم الصفحات على المفاتيح. إذا كانت لديك أسئلة أو كنت بحاجة إلى مساعدة، سأكون سعيدًا بمساعدتك (форум, تويتر, نموذج الاتصال) (ملاحظة: من تجربتي مع ماركوس أستطيع أن أقول إنه متحمس حقًا لنشر هذا الموضوع).

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

اختتام

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

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

المصدر: https://use-the-index-luke.com/no-offset
المؤلف: ماركوس فيناند

المصدر: www.habr.com

إضافة تعليق