داخل PostgreSQL › الصفوف المكتفية بالكومة (HOT) 7 / 13 السابق التالي

الصفوف المكتفية بالكومة (HOT)

7.1. الصفوف المكتفية بالكومة (Heap Only Tuple, HOT)

نفّذ PostgreSQL 8.3 (عام 2008) تقنية الصفوف المكتفية بالكومة (HOT) لاستخدام صفحات الفهرس والجدول معاً بفعالية عندما يُخزَّن الصف المحدَّث في الصفحة نفسها التي يوجد فيها الصف القديم. كما تقلّل HOT الحاجة إلى معالجة VACUUM.

ولأن ملف README.HOT في دليل الشيفرة المصدرية يصف HOT بالتفصيل، لا يقدّم هذا الفصل سوى مقدمة موجزة.

يصف القسم 7.1.1 كيف يحدّث PostgreSQL صفاً بدون HOT لتوضيح المشكلات التي تحلّها HOT. ثم يصف القسم 7.1.2 كيفية عمل HOT.

7.1.1. تحديث صف بدون HOT

افترض أن الجدول ’tbl’ له عمودان: ‘id’ (المفتاح الأساسي) و‘data’.

testdb=# \d tbl
                Table "public.tbl"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 id     | integer |           | not null |
 data   | text    |           |          |
Indexes:
    "tbl_pkey" PRIMARY KEY, btree (id)

يحتوي الجدول ’tbl’ على 1,000 صف. ويُخزَّن الصف الأخير (id = 1000) في الصفحة الخامسة من الجدول. ويشير صف الفهرس المقابل (key = 1000) إلى هذا الصف بمعرّف TID هو ‘(5, 1)’. انظر الشكل 7.1(أ).

الشكل 7.1. تحديث صف بدون HOT

لنتأمّل كيف يُحدَّث الصف الأخير بدون HOT.

testdb=# UPDATE tbl SET data = 'B' WHERE id = 1000;

في هذه الحالة، يُدرج PostgreSQL كلاً من صف الجدول الجديد وصف فهرس جديد. انظر الشكل 7.1(ب).

يستهلك إدراج صفوف الفهرس مساحة صفحات الفهرس. علاوةً على ذلك، فإن كلفة إدراج صفوف الفهرس وتفريغها مرتفعة. وتقلّل HOT من تأثير هذه المشكلات.

7.1.2. كيف تعمل HOT

عند تحديث صف باستخدام HOT، لا يُدرج PostgreSQL صف فهرس جديداً إذا كان الصف المحدَّث مخزَّناً في صفحة الجدول نفسها التي يوجد فيها الصف القديم. وبدلاً من ذلك، يضبط بتّة HEAP_HOT_UPDATED في الحقل t_informask2 الخاص بالصف القديم وبتّة HEAP_ONLY_TUPLE في الصف الجديد. انظر الشكلين 7.2 و7.3.

الشكل 7.2. تحديث صف باستخدام HOT

فمثلاً، في هذه الحالة، يُوسَم Tuple_1 بـ HEAP_HOT_UPDATED ويُوسَم Tuple_2 بـ HEAP_ONLY_TUPLE.

بالإضافة إلى ذلك، يستخدم PostgreSQL هاتين البتّتين بصرف النظر عن تنفيذ عمليتي التشذيب (pruning) وإزالة التشظّي (defragmentation) (الموضّحتين أدناه).

الشكل 7.3. بتّتا HEAP_HOT_UPDATED وHEAP_ONLY_TUPLE

فيما يلي وصف لكيفية وصول PostgreSQL إلى الصفوف المحدَّثة عبر مسح فهرس مباشرةً بعد تحديث HOT. انظر الشكل 7.4(أ).

الشكل 7.4. تشذيب مؤشرات الأسطر

  • (1) إيجاد صف الفهرس الذي يشير إلى الصف الهدف.
  • (2) الوصول إلى مؤشر السطر [1] الذي يشير إليه صف الفهرس.
  • (3) قراءة Tuple_1.
  • (4) قراءة Tuple_2 عبر t_ctid الخاص بـ Tuple_1.

يقرأ PostgreSQL الصفين معاً ويحدّد أيّهما مرئي باستخدام آلية التحكّم بالتزامن الموضّحة في الفصل 5.

غير أن مشكلة تنشأ إذا أُزيلت الصفوف الميتة من صفحات الجدول. ففي الشكل 7.4(أ)، إذا أُزيل Tuple_1 بوصفه صفاً ميتاً، لا يستطيع الفهرس الوصول إلى Tuple_2.

ولحلّ ذلك، يعيد PostgreSQL توجيه مؤشر السطر الخاص بالصف القديم إلى مؤشر السطر الخاص بالصف الجديد في الوقت المناسب. وتُسمى هذه العملية التشذيب (pruning). ويوضّح الشكل 7.4(ب) كيف يصل PostgreSQL إلى الصفوف بعد التشذيب.

  • (1) إيجاد صف الفهرس.
  • (2) الوصول إلى مؤشر السطر [1] الذي يشير إليه صف الفهرس.
  • (3) الوصول إلى مؤشر السطر [2] عبر مؤشر السطر المعاد توجيهه.
  • (4) قراءة Tuple_2 الذي يشير إليه مؤشر السطر [2].

يُنفَّذ التشذيب، إن أمكن، أثناء أوامر SQL مثل SELECT وUPDATE وINSERT وDELETE. ولا يصف هذا التوثيق التوقيت الدقيق للتنفيذ لأنه معقّد؛ والتفاصيل في ملف README.HOT.

كما يزيل PostgreSQL الصفوف الميتة في الوقت المناسب، على غرار عملية التشذيب. وتُسمى هذه العملية إزالة التشظّي (defragmentation). ويوضّح الشكل 7.5 إزالة التشظّي بواسطة HOT.

الشكل 7.5. إزالة تشظّي الصفوف الميتة

كلفة إزالة التشظّي أقل من كلفة معالجة VACUUM العادية لأنها لا تتضمن إزالة صفوف الفهرس.

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

7.1.3. الحالات التي لا تتوفر فيها HOT

لفهم HOT بوضوح، تُعرض فيما يلي حالتان لا يمكن فيهما استخدام HOT:

  • (أ) عندما يُخزَّن الصف المحدَّث في صفحة مختلفة عن الصف القديم، يجب على PostgreSQL إدراج صف فهرس جديد. انظر الشكل 7.6(أ).
  • (ب) عندما تُحدَّث قيمة مفتاح صف الفهرس، يجب على PostgreSQL إدراج صف فهرس جديد. انظر الشكل 7.6(ب).

الشكل 7.6. الحالات التي لا تتوفر فيها HOT.

7.2. المسح بالفهرس فقط (Index-Only Scans)

يقلّل المسح بالفهرس فقط (index-only scans) (ويُسمى غالباً الوصول بالفهرس فقط) كلفة الإدخال/الإخراج باستخدام مفتاح الفهرس مباشرةً دون الوصول إلى صفحات الجدول. ويحدث ذلك عندما يشمل مفتاح الفهرس جميع المدخلات المستهدفة في أمر SELECT. وتوفّر هذه التقنية جميع أنظمة RDBMS التجارية تقريباً، مثل DB2 وOracle. وقد قدّم PostgreSQL هذا الخيار في الإصدار 9.2 (عام 2012).

يصف المثال التالي كيفية عمل المسح بالفهرس فقط في PostgreSQL.

يعتمد المثال على الافتراضات التالية:

تعريف الجدول: يُعرَّف الجدول ’tbl’ كما يلي:

testdb=# \d tbl
      Table "public.tbl"
 Column |  Type   | Modifiers
--------+---------+-----------
 id     | integer |
 name   | text    |
 data   | text    |
Indexes:
    "tbl_idx" btree (id, name)

الفهرس: يتكوّن الفهرس ’tbl_idx’ من عمودين: ‘id’ و’name’.

الصفوف: يحتوي الجدول ’tbl’ على الصفوف التالية:

  • Tuple_18: المعرّف 18، والاسم ‘Queen’؛ مخزَّن في الصفحة 0.
  • Tuple_19: المعرّف 19، والاسم ‘BOSTON’؛ مخزَّن في الصفحة 1.

الظهور: جميع الصفوف في الصفحة 0 مرئية؛ أما الصفوف في الصفحة 1 فليست كذلك. ويُسجَّل ظهور كل صفحة في خريطة الظهور (VM) المقابلة. (راجع القسم 6.2 لتفاصيل VM.)

يوضّح أمر SELECT التالي كيفية قراءة PostgreSQL لهذه الصفوف:

testdb=# SELECT id, name FROM tbl WHERE id BETWEEN 18 and 19;
 id |  name
----+--------
 18 | Queen
 19 | Boston
(2 rows)

يسترجع هذا الاستعلام بيانات من العمودين ‘id’ و’name’. ولأن الفهرس ’tbl_idx’ يحتوي على العمودين معاً، يبدو الوصول إلى صفحات الجدول غير ضروري في البداية.

غير أنه من حيث المبدأ يجب على PostgreSQL فحص ظهور الصفوف. فصفوف الفهرس لا تحتوي على معلومات المعاملات، مثل الحقلين t_xmin وt_xmax الموجودين في صفوف الكومة (الموضّحين في القسم 5.2). وبالتالي يجب على PostgreSQL عادةً الوصول إلى بيانات الجدول للتحقق من ظهور صفوف الفهرس.

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

في هذا المثال، لا يصل PostgreSQL إلى Tuple_18 لأن الصفحة 0 مُعلَّمة بأنها مرئية في VM. وفي المقابل، يجب عليه الوصول إلى Tuple_19 للتعامل مع التحكّم بالتزامن لأن الصفحة 1 ليست مُعلَّمة بأنها مرئية بالكامل. انظر الشكل 7.7.

الشكل 7.7. كيف يعمل المسح بالفهرس فقط