عند العمل مع إطار عمل Ruby on Rails، نتعامل عادةً مع قواعد البيانات العلائقية مثل MySQL أو PostgreSQL. عند تحديد عمليات الترحيل باستخدام عمليات ترحيل السجلات النشطة، نصادف ما يسمى بالفهارس، ولكن المبتدئين غالباً ما لا يفهمون تماماً الفهارس وما هي الفوائد التي تجلبها.
عند العمل مع إطار عمل Ruby on Rails، نتعامل عادةً مع قواعد البيانات العلائقية مثل MySQL أو PostgreSQL. عند تحديد عمليات الترحيل باستخدام عمليات ترحيل السجلات النشطة، نصادف ما يسمى بالفهارس، ولكن المبتدئين غالباً ما لا يفهمون تماماً الفهارس وما هي الفوائد التي تجلبها.
في هذا المنشور، أود أن أشرح ما هي الفهارس، وما هي أغراضها وأقدم بعض الممارسات الجيدة حول كيفية استخدامها.
قاعدة البيانات
هناك العديد من محركات قواعد البيانات، ومن أكثرها شيوعًا محركات قواعد البيانات المذكورة سابقًا MySQL أو PostgreSQL أو Oracle أو Microsoft SQL Server. جميعها قواعد بيانات علائقية، مما يعني أن جميع أجزاء البيانات مرتبطة ببعضها البعض ومخزنة في جداول. يُسمى كل صف في الجدول بسجل، ولكل منها معرّف فريد خاص به (id). يمكنك التحقق من ترتيب محركات قواعد البيانات الأكثر شيوعًا على https://db-engines.com/en/ranking. ستجد أيضًا بعض قواعد البيانات غير العلائقية هناك، مثل MongoDB.
إنشاء فهرس
يمكن أن تحتوي الجداول في قواعد بياناتنا على عدد يتراوح بين بضعة إلى عدة عشرات من الأعمدة - وفي الحالات القصوى قد يصل إلى عدة مئات من الأعمدة. ضع في اعتبارك أن كل جدول يمكن أن يحتوي على عدد غير محدود من الصفوف. لا ينتج هذا العدد مباشرةً من بنية قاعدة البيانات ويجب أن نفترض دائمًا أن عدد السجلات سيزداد تباعًا، ونتيجة لذلك، ستنمو قاعدة بياناتنا. قد تكون الافتراضات الأولية والاستعلامات المكتوبة في التطبيقات الحالية رائعة بالنسبة لعدد صغير أو متوسط من السجلات، ولكن مع مرور الوقت، عندما تصل المزيد من البيانات، يتوقف اتصال التطبيق بقاعدة البيانات عن أن يكون فعالاً.
يتمثل دور المبرمج في كتابة استعلامات لاسترجاع بعض البيانات من الجدول أو الجداول، لكن الطريقة المثلى لمعالجة الاستعلام تعتمد على محرك قاعدة البيانات. تذكّر أن محركات قواعد البيانات تقوم بتحميل البيانات من القرص إلى الذاكرة ثم تفحصها. هذا يعني أنه إذا قام العديد من المستخدمين بإجراء عمليات معقدة في نفس الوقت، فسيتعين على العديد منهم انتظار دورهم بسبب نقص الموارد اللازمة لتنفيذ عمليات البحث الخاصة بهم. وهذا هو سبب أهمية الفهارس ذات الصلة.
ويكي: الفهرس - بنية بيانات تزيد من سرعة إجراء عمليات البحث على جدول.
بالنسبة لكل فهرس، نحتاج إلى تحديد مفاتيح (لعمود واحد أو عدة أعمدة) سيتم استخدامها للبحث عن السجلات في الجدول. سيتم فرز البيانات الموجودة في الفهرس باستخدام المفتاح الذي تم تحديده مسبقًا، مما سيسرّع بشكل كبير من عملية البحث عن البيانات في الجدول. أبسط مثال من الحياة اليومية هو دليل الهاتف الذي يتم فيه فرز الأشخاص حسب الاسم واللقب. يمكن القول أن فهرسنا في هذه الحالة سيكون الاسم الأول والأخير.
كيف تختار أفضل مفتاح فهرس؟ الأمر ليس صعبًا - فقط تذكر بعض القواعد. أنشئ فهرسًا بناءً على الأعمدة التي:
- غالبًا ما تُستخدم في استفساراتنا (أين),
- مع بعضها البعض تعطي قيمة فريدة (أي قيمة تشير إلى صف واحد فقط),
- ستُستخدم فيما يُسمى بأعمدة الربط (JOIN),
- إعطاء المفاتيح الأكثر انتقائية، أي تلك التي تُرجع أقل عدد من الأسطر عند كتابة استعلام.
إذا كنا نعرف بالفعل المفاتيح التي ستكون مثالية لجدولنا، يمكننا أيضًا أن نسأل أنفسنا عن عدد الفهارس التي نحتاجها. في هذه الحالة، من الأفضل معرفة الاستعلامات التي ستشير إلى جدولنا بالفعل في مرحلة التصميم.
دعونا ننشئ فهارس لاستعلامات محددة ستظهر، ولكن لا نكتبها لكل عمود. تحتاج الفهارس، مثلها مثل الجداول، إلى التخزين في مكان ما، لذلك عندما ننشئ جداول بفهرس لكل عمود، يجب أن نأخذ في الاعتبار أن مقدار المساحة المستخدمة يمكن أن يزيد بشكل كبير.
إنشاء فهرس فريد من نوعه
هناك مسألة أخرى نحتاج إلى التفكير فيها وهي التفرد. يجدر بنا قضاء خمس دقائق إضافية في التفكير فيما إذا كان فهرسنا فريدًا حقًا. وبهذه الطريقة، نخبر مُحسِّن الاستعلام أنه لا يجب أن يتوقع تكرارًا في الاستعلام. على سبيل المثال، عناوين البريد الإلكتروني:
متجمد متجمد: صحيح
صنف إنشاء مستخدمين < ActiveRecord::Migration[6.0]
تعريف التغيير
إنشاء جدول: المستخدمون do |t|
t.string :البريد الإلكتروني، فارغ: خطأ
النهاية
إضافة فهرس: المستخدمين، :بريد إلكتروني، فريد: صحيح
النهاية
النهاية
في مثال محرك PostgreSQL، سأعرض الفرق في سرعة الاستعلام على عمود البريد الإلكتروني مع فهرس فريد وبدون فهرس.
1. يمكنك استخدام عينة الكود مقتطفات على قاعدة البيانات الخاصة بك لتتمكن من اختبار المثال أدناه. أولاً، لنقم بإنشاء جدول فارغ بعمود واحد:
إنشاء جدول إنشاء مستخدمين (
البريد الإلكتروني فارشار
);
2. دعنا ننشئ 10000 سجل للاختبار:
<، $
ابدأ بالنسبة ل i في 1...10000 لوب
INSERT INSERT INTO Users القيم ((حدد 'مستخدم' || i || '@example.com'));
نهاية اللولب؛ نهاية;
$;
سنستخدم EXPLAIN ANALYZE للتحقق من مدى سرعة معالجة استعلامنا عندما نريد العثور على مستخدم معين في قاعدة البيانات.
EXPLAIN ANALYZE SELECT email FROM users WHERE email = 'user890example.com';
أجبرنا استعلامنا على التكرار حول الجدول بأكمله بحثًا عن السجل الذي يهمنا.
تسمى هذه العملية المسح المتسلسل. في هذه الحالة، فإن قراءة الجدول بأكمله وتصفية صفوف معينة هي أفضل طريقة للقيام بالمهمة.
ستعمل PostgreSQL على تصفية الأسطر غير الضرورية وإرجاع الأسطر التي تهمنا ببساطة. هذا حقًا أفضل شيء يمكن القيام به في هذه الحالة. المسح المتسلسل ليس سيئًا دائمًا، فهناك حالات يكون فيها المسح المتسلسل مثاليًا.
4. حان الوقت الآن للتحقق من الاستعلام الذي تم إجراؤه بالفعل على الجدول الذي يحتوي على فهرس INDEX UNIQUE. لنقم بتعيين الفهرس وتنفيذ الاستعلام.
شرح تحليل حدد حدد البريد الإلكتروني من المستخدمين حيث البريد الإلكتروني = 'user890example.com';
هذه المرة استفادت PostgreSQL من مسح الفهرس لأن جميع الأعمدة المطلوبة موجودة بالفعل في الفهرس.
سيكون تحديد بضعة أسطر فقط فعالاً للغاية عند استخدام الفهرس. ومع ذلك، إذا تم تحديد المزيد من البيانات، فإن مسح الفهرس والجدول سيستغرق وقتًا طويلاً جدًا.
الملخص
كما ترى، فإن وقت تنفيذ استعلام على عمود يحتوي على فهرس أقصر بكثير (في المثال الموضح، ينخفض من 1.267 مللي ثانية إلى 0.111 مللي ثانية، أي ما يعادل 91.241 تيرابايت في الثانية!) الفرق الأكثر أهمية هو الطريقة التي يبحث بها PostgreSQL عن السجل الذي يهمنا. في الحالة الأولى، كان على محرك قاعدة البيانات أن يبحث في الجدول بأكمله عن السجل الذي نحتاج إليه. أما في الحالة الثانية، فإن بنية الفهرس مرتبة وفريدة من نوعها، وبالتالي كان المحرك يعرف مكان السجل، مما سرّع بشكل كبير من وقت معالجة الاستعلام.
في حالة قواعد البيانات الكبيرة والاستعلامات المعقدة للغاية، يمكن للفهارس المضبوطة بشكل صحيح أن تسرّع عمل تطبيقك بشكل كبير دون الحاجة إلى زيادة سرعة الجهاز الذي تبحث في قاعدة البيانات عليه.
من الجدير بالذكر أن إنشاء فهارس على كل عمود ليس ممارسة جيدة. ستؤدي الفهارس المنشأة إلى تسريع عمل المُحسِّن عند البحث عن البيانات ذات الأهمية، ولكنها في الوقت نفسه تبطئ من عملية إدراج فهارس جديدة وتحديث الفهارس الموجودة.