> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# تخطيط قاموس cache

> تخزين قاموس في cache داخل الذاكرة بحجم ثابت.

يخزّن نوع تخطيط القاموس `cached` القاموس في cache يحتوي على عدد ثابت من الخلايا.
وتتضمن هذه الخلايا العناصر الأكثر استخدامًا.

يكون مفتاح القاموس من النوع [UInt64](/ar/reference/data-types/int-uint).

عند البحث عن قيمة في القاموس، يُبحث أولًا في cache. ولكل block من البيانات، تُطلب جميع المفاتيح التي لا توجد في cache أو التي انتهت صلاحيتها من المصدر باستخدام `SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)`. ثم تُكتب البيانات المستلمة إلى cache.

ينطبق ذلك عند البحث عن مفتاح — باستخدام `dictGet` ودوال القاموس الأخرى. أما قراءة القاموس **كجدول** باستخدام `SELECT ... FROM <dictionary>` فتختلف: فلأن cache لا يحتفظ بسجل بالمفاتيح الموجودة، تُعدِّد القراءة فقط الخلايا الموجودة في cache في تلك اللحظة والتي تحمل قيمة، ويكون `WHERE` على المفتاح عامل تصفية عاديًا لتلك الخلايا، وليس قائمة مفاتيح لجلبها. ولا يمكن اكتشاف مفتاح غير موجود في cache بهذه الطريقة، مهما كان ما ينص عليه `WHERE`. كما أن المفتاح الذي *جرى* البحث عنه ولم يُعثر عليه في المصدر لا يكون مرئيًا أيضًا: إذ يتذكر cache هذا الإخفاق كخلية افتراضية، وتتخطى قراءة الجدول الخلايا الافتراضية. كما أن الخلايا الموجودة ليست بمنأى عن المصدر: فالخلية منتهية الصلاحية تُقرأ عبر المسار نفسه الذي يسلكه `dictGet`، ولذلك يُعاد طلبها من المصدر — بشكل متزامن، أو بشكل غير متزامن إذا كان `allow_read_expired_keys` مفعّلًا.

```sql theme={null}
CREATE DICTIONARY cache_dict (id UInt64, data String) PRIMARY KEY id
SOURCE(CLICKHOUSE(TABLE 'cache_src')) LIFETIME(MIN 0 MAX 900) LAYOUT(CACHE(SIZE_IN_CELLS 1000));

-- nothing is cached yet, so nothing comes back and the source is not queried
SELECT count() FROM cache_dict WHERE id IN (1, 2, 3);
0

-- looking the keys up populates the cache
SELECT dictGet('cache_dict', 'data', toUInt64(number + 1)) FROM numbers(3);

-- and now the same read sees them
SELECT count() FROM cache_dict WHERE id IN (1, 2, 3);
3
```

لذا فإن قاموس cache مُصمَّم ليُستخدم عبر دوال القاموس. إذا كنت بحاجة إلى أن يصل البحث عن مفاتيح عشوائية إلى المصدر دائمًا، فاستخدم `dictGet` مع تخطيط [direct](/ar/reference/statements/create/dictionary/layouts/direct)، الذي يستعلم من المصدر عند كل عملية بحث ولا يخزّن شيئًا في cache. لاحظ أن قراءة قاموس `direct` كجدول ليست جلبًا بالمفتاح أيضًا: إذ يُحمِّل `SELECT ... FROM <dictionary> WHERE key IN (...)` المصدر بأكمله ثم يُجري التصفية بعد ذلك، لأن ClickHouse لا يدفع عامل تصفية المفتاح إلى داخل القاموس. ولقراءة قاموس كجدول، استخدم تخطيطًا يحتفظ به كاملًا، مثل [flat](/ar/reference/statements/create/dictionary/layouts/flat) أو [hashed](/ar/reference/statements/create/dictionary/layouts/hashed).

إذا لم يُعثر على المفاتيح في القاموس، فستُنشأ مهمة لتحديث cache وتُضاف إلى قائمة انتظار التحديث. ويمكن التحكم في خصائص قائمة انتظار التحديث باستخدام الإعدادات `max_update_queue_size`, `update_queue_push_timeout_milliseconds`, `query_wait_timeout_milliseconds`, `max_threads_for_updates`.

بالنسبة إلى قواميس cache، يمكن ضبط [lifetime](/ar/reference/statements/create/dictionary/lifetime) لانتهاء صلاحية البيانات في cache. وإذا مرّ وقت أطول من `lifetime` منذ تحميل البيانات في خلية معيّنة، فلن تُستخدم قيمة الخلية ويصبح المفتاح منتهي الصلاحية. ويُعاد طلب المفتاح في المرة التالية التي يلزم فيها استخدامه. ويمكن تهيئة هذا السلوك باستخدام الإعداد `allow_read_expired_keys`.

تُعد هذه أقل طرق تخزين القواميس كفاءةً بين جميع الطرق. وتعتمد سرعة cache بدرجة كبيرة على صحة الإعدادات وسيناريو الاستخدام. ولا يحقق القاموس من النوع cache أداءً جيدًا إلا عندما تكون معدلات النجاح مرتفعة بما يكفي (الموصى به 99% فأكثر). ويمكنك عرض متوسط معدل النجاح في جدول [system.dictionaries](/ar/reference/system-tables/dictionaries).

إذا كان الإعداد `allow_read_expired_keys` مضبوطًا على 1، بينما القيمة الافتراضية هي 0، فسيتمكن القاموس من دعم التحديثات غير المتزامنة. وإذا طلب client مفاتيح وكانت جميعها موجودة في cache، لكن بعضًا منها منتهي الصلاحية، فسيُرجع القاموس المفاتيح منتهية الصلاحية إلى client ويطلبها بشكل غير متزامن من المصدر.

لتحسين أداء cache، استخدم استعلامًا فرعيًا مع `LIMIT`، واستدعِ الدالة باستخدام القاموس من خارجها.

جميع أنواع المصادر مدعومة.

مثال على الإعدادات:

<Tabs>
  <Tab title="DDL">
    ```sql theme={null}
    LAYOUT(CACHE(SIZE_IN_CELLS 1000000000))
    ```
  </Tab>

  <Tab title="ملف الإعدادات">
    ```xml theme={null}
    <layout>
        <cache>
            <!-- حجم cache، بعدد الخلايا. يُقرَّب إلى أقرب قوة للعدد 2. -->
            <size_in_cells>1000000000</size_in_cells>
            <!-- السماح بقراءة المفاتيح منتهية الصلاحية. -->
            <allow_read_expired_keys>0</allow_read_expired_keys>
            <!-- الحد الأقصى لحجم قائمة انتظار التحديث. -->
            <max_update_queue_size>100000</max_update_queue_size>
            <!-- المهلة القصوى بالمللي ثانية لإدراج مهمة التحديث في قائمة الانتظار. -->
            <update_queue_push_timeout_milliseconds>10</update_queue_push_timeout_milliseconds>
            <!-- الحد الأقصى لمهلة الانتظار بالمللي ثانية حتى تكتمل مهمة التحديث. -->
            <query_wait_timeout_milliseconds>60000</query_wait_timeout_milliseconds>
            <!-- الحد الأقصى لعدد الخيوط لتحديث قاموس cache. -->
            <max_threads_for_updates>4</max_threads_for_updates>
        </cache>
    </layout>
    ```
  </Tab>
</Tabs>

<br />

اضبط حجم cache بحيث يكون كبيرًا بما يكفي. ستحتاج إلى التجربة لاختيار عدد الخلايا:

1. اضبط قيمة مبدئية.
2. شغّل الاستعلامات حتى يمتلئ cache بالكامل.
3. قيّم استهلاك الذاكرة باستخدام جدول `system.dictionaries`.
4. زِد عدد الخلايا أو قلّله حتى تصل إلى استهلاك الذاكرة المطلوب.

<Note>
  لا يُنصح باستخدام ClickHouse كمصدر لهذا التخطيط. تتطلب عمليات البحث في القاموس قراءات نقطية عشوائية، وهذا ليس نمط الوصول الذي جرى تحسين ClickHouse من أجله.
</Note>
