في عالم Postgres ، تعد الفهارس مهمة للتنقل في مستودع قاعدة البيانات بكفاءة (تسمى الكومة ، الكومة). لا يدعم Postgres المجموعات الخاصة به ، وتتسبب بنية MVCC في تراكم العديد من إصدارات نفس المجموعة. لذلك ، من المهم جدًا أن تكون قادرًا على إنشاء فهارس فعالة والمحافظة عليها لدعم التطبيقات.
فيما يلي بعض النصائح لتحسين وتحسين استخدام الفهارس.
ملاحظة: تعمل الاستعلامات الموضحة أدناه على قاعدة بيانات نموذج باجيلا غير معدلة.باستخدام تغطية الفهارس
دعنا نراجع طلب استرداد عناوين البريد الإلكتروني للمستخدمين غير النشطين. يحتوي جدول
customer
على عمود
active
، والطلب بسيط:
pagila=
يستدعي الاستعلام التسلسل الكامل لمسح جدول
customer
. لنقم بإنشاء فهرس للعمود
active
:
pagila=
ساعد ، تحولت المسح اللاحق إلى "
index scan
". هذا يعني أن Postgres ستقوم بمسح فهرس
idx_cust1
، ثم تستمر في البحث في كومة الجدول لقراءة قيم الأعمدة الأخرى (في هذه الحالة ، عمود
email
) الذي يحتاجه الاستعلام.
قدم بوستجرس 11 تغطية الفهارس. إنها تتيح لك تضمين عمود إضافي واحد أو أكثر في الفهرس نفسه - يتم تخزين قيمها في مخزن بيانات الفهرس.
إذا استخدمنا هذه الميزة وأضفنا قيمة بريد إلكتروني داخل الفهرس ، فلن تحتاج Postgres إلى البحث عن قيمة
email
في كومة الذاكرة المؤقتة للجدول. دعونا نرى ما اذا كان هذا يعمل:
pagila=
يخبرنا "
Index Only Scan
" أن الاستعلام يحتاج الآن فهرس واحد فقط ، مما يساعد على تجنب كل القرص I / O لقراءة كومة الجدول.
اليوم ، فهارس التغطية متاحة فقط للأشجار ب. ومع ذلك ، في هذه الحالة ، ستكون جهود المرافقة أعلى.
باستخدام فهارس جزئية
الفهارس الجزئية فقط مجموعة فرعية من الصفوف في جدول. هذا يحفظ حجم الفهارس ومسح أسرع.
لنفترض أننا بحاجة إلى الحصول على قائمة بعناوين البريد الإلكتروني من عملائنا في كاليفورنيا. سيكون الطلب مثل هذا:
SELECT c.email FROM customer c JOIN address a ON c.address_id = a.address_id WHERE a.district = 'California'; which has a query plan that involves scanning both the tables that are joined: pagila=
ما الفهارس العادية سوف تعطينا:
pagila=
تم استبدال فحص
address
بمسح فهرس
idx_address1
، ثم تم فحص كومة الذاكرة المؤقتة
address
.
نظرًا لأن هذا استعلام متكرر ويحتاج إلى التحسين ، فيمكننا استخدام فهرس جزئي بفهرسة تلك الصفوف فقط بعناوين تكون فيها منطقة
'California'
:
pagila=
الآن يقرأ الطلب
idx_address2
فقط ولا يلمس جدول
address
.
باستخدام فهارس متعدد القيم
قد لا تحتوي بعض الأعمدة التي تحتاج إلى فهرستها على نوع بيانات عددية.
jsonb
أنواع
jsonb
مثل
jsonb
arrays
و
tsvector
على قيم متعددة أو متعددة. إذا كنت بحاجة إلى فهرسة مثل هذه الأعمدة ، فعادة ما يتعين عليك البحث عن جميع القيم الفردية في هذه الأعمدة.
دعنا نحاول العثور على أسماء جميع الأفلام التي تحتوي على مقتطفات من مقاطع غير ناجحة. يحتوي جدول
film
على عمود نص يسمى
special_features
. إذا كان الفيلم يحتوي على "خاصية خاصة" ، فإن العمود يحتوي على عنصر في شكل صفيف نص
Behind The Scenes
. للبحث عن جميع هذه الأفلام ، نحتاج إلى تحديد كل الصفوف التي تحتوي على "Behind The Scenes"
لأي قيم في مجموعة
special_features
:
SELECT title FROM film WHERE special_features @> '{"Behind The Scenes"}';
يتحقق مشغل الاحتواء
@>
لمعرفة ما إذا كان الجانب الأيمن عبارة عن مجموعة فرعية من الجانب الأيسر.
خطة الطلب:
pagila=
الذي يطلب مسح كومة كامل بتكلفة 67.
دعونا نرى ما إذا كان مؤشر B-tree العادي يساعدنا:
pagila=
لم يتم النظر في المؤشر. لا يعرف فهرس B-tree وجود عناصر فردية في القيم المفهرسة.
نحن بحاجة إلى مؤشر الجن.
pagila=
يدعم فهرس GIN مقارنة القيم الفردية مع القيم المركبة المفهرسة ، ونتيجة لذلك ، يتم تقليل تكلفة خطة الاستعلام بأكثر من النصف.
تخلص من الفهارس المكررة
تتراكم الفهارس بمرور الوقت ، وفي بعض الأحيان قد يحتوي الفهرس الجديد على نفس التعريف مثل أحد التعريفات السابقة. للحصول على تعريفات SQL قابلة للقراءة من الفهارس ، يمكنك استخدام عرض الكتالوج
pg_indexes
. يمكنك أيضًا العثور بسهولة على نفس التعريفات:
SELECT array_agg(indexname) AS indexes, replace(indexdef, indexname, '') AS defn FROM pg_indexes GROUP BY defn HAVING count(*) > 1; And here's the result when run on the stock pagila database: pagila=
فهارس مجموعة فرعية
قد يحدث تراكم العديد من الفهارس ، أحدها يفهرس مجموعة فرعية من الأعمدة التي تقوم بفهرسة فهارس أخرى. يمكن أن يكون هذا أمرًا مرغوبًا أم لا - فبإمكان مجموعة فرعية أن تؤدي إلى إجراء مسح ضوئي فقط عن طريق فهارس ، وهو أمر جيد ، ولكن يمكن أن يستغرق مساحة كبيرة جدًا ، أو لم يعد يستخدم الاستعلام الذي تم إعداد هذه المجموعة الفرعية لتحسينه.
إذا كنت بحاجة إلى أتمتة تعريف مثل هذه الفهارس ، يمكنك البدء بـ
pg_index من جدول
pg_catalog
.
الفهارس غير المستخدمة
أثناء تطوير التطبيقات التي تستخدم قواعد البيانات ، يتم تطوير الاستعلامات التي تستخدمها. قد لا يتم استخدام الفهارس التي تمت إضافتها مسبقًا بواسطة أي استعلام. في كل مرة يتم فيها مسح الفهرس ، يتم تمييزه بواسطة مدير الإحصائيات ، وفي
pg_stat_user_indexes
كتالوج النظام ، يمكنك رؤية قيمة
idx_scan
، وهي عداد تراكمي. تتبع هذه القيمة على مدى فترة زمنية (على سبيل المثال ، شهر) سيعطي فكرة جيدة عن الفهارس التي لا يتم استخدامها ويمكن حذفها.
فيما يلي طلب للحصول على تعدادات المسح الحالية لجميع المؤشرات في المخطط
'public'
:
SELECT relname, indexrelname, idx_scan FROM pg_catalog.pg_stat_user_indexes WHERE schemaname = 'public'; with output like this: pagila=
إعادة إنشاء الفهارس مع عدد أقل من الأقفال
غالبًا ما يجب إعادة إنشاء الفهارس ، على سبيل المثال ، عندما يتم تضخيم حجمها ، ويمكن لإعادة الإنشاء تسريع عملية المسح. أيضا ، قد يكون معطوبا المؤشرات. قد يتطلب تغيير معلمات الفهرس أيضًا إعادة إنشائها.
تمكين إنشاء فهرس متوازي
في PostgreSQL 11 ، يكون إنشاء فهرس B-Tree منافسًا. لتسريع عملية الخلق ، يمكن استخدام العديد من العمال الموازيين. ومع ذلك ، تأكد من تعيين معلمات التكوين هذه بشكل صحيح:
SET max_parallel_workers = 32; SET max_parallel_maintenance_workers = 16;
القيم الافتراضية صغيرة جدًا. من الناحية المثالية ، يجب زيادة هذه الأرقام مع عدد مراكز المعالج. اقرأ
الوثائق لمزيد من التفاصيل.
إنشاء مؤشر الخلفية
يمكنك إنشاء فهرس في الخلفية باستخدام المعلمة
CONCURRENTLY
للأمر
CREATE INDEX
:
pagila=
يختلف إجراء إنشاء الفهرس عن الإجراء المعتاد في أنه لا يتطلب تأمين الجدول ، وبالتالي لا يمنع عمليات الكتابة. من ناحية أخرى ، يستغرق المزيد من الوقت ويستهلك المزيد من الموارد.
يوفر Postgres العديد من الخيارات المرنة لإنشاء فهارس وطرق لحل أي حالات معينة ، بالإضافة إلى توفير طرق لإدارة قاعدة البيانات في حالة النمو الهائل للتطبيق الخاص بك. نأمل أن تساعدك هذه النصائح في جعل استفساراتك سريعة وقاعدة البيانات جاهزة للتوسع.