> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# تحديد اختناقات الاستعلامات

> استخدم مقارنة متكررة عبر ثلاث عمليات تشغيل لتحديد الاختناقات في استعلامات ClickHouse البطيئة

export const Image = ({img, alt, size = "lg", background}) => {
  const normalizedSize = ["sm", "md", "lg"].includes(size) ? size : "lg";
  const backgroundColor = background === "white" ? "white" : background === "black" ? "rgb(31 31 28)" : undefined;
  return <div className={`ch-image-${normalizedSize}`}>
      <Frame>
        <img src={img} alt={alt} style={{
    backgroundColor
  }} />
      </Frame>
    </div>;
};

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

<div id="before-you-begin">
  ## قبل أن تبدأ
</div>

ابدأ بنمط متكرر من الاستعلامات البطيئة التي تريد التحقيق فيها. إذا لم تكن قد حددت نمطًا بعد، فراجع [تشخيص الاستعلامات البطيئة](/docs/ar/guides/clickhouse/performance-and-monitoring/diagnose-slow-queries) للتعرّف على الخطوات.

لتشغيل الأمثلة الواردة في هذا الدليل كما كُتبت، أنشئ الجدول `nyc_taxi.trips_small_inferred` وحمّله إذا لم تكن قد فعلت ذلك مسبقًا:

<Accordion title="إعداد مجموعة البيانات النموذجية">
  <Note>
    يبلغ حجم ملف Parquet المصدر نحو 5.8 GB. قد يستغرق تحميله عدة دقائق، حسب الشبكة والموارد المتاحة.
  </Note>

  ```sql theme={null}
  CREATE DATABASE IF NOT EXISTS nyc_taxi;
  USE nyc_taxi;

  CREATE TABLE nyc_taxi.trips_small_inferred
  ORDER BY () EMPTY
  AS SELECT *
  FROM s3(
      'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/clickhouse-academy/nyc_taxi_2009-2010.parquet',
      NOSIGN,
      Parquet
  );

  INSERT INTO nyc_taxi.trips_small_inferred
  SELECT *
  FROM s3(
      'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/clickhouse-academy/nyc_taxi_2009-2010.parquet',
      NOSIGN,
      Parquet
  );
  ```
</Accordion>

يستخدم الجدول النموذجي `ORDER BY ()`، لذا لا يمكن لفلتر التاريخ فيه استخدام مفتاح ترتيب لاستبعاد البيانات أثناء القراءة. استخدم المثال للتدرّب على منهجية المقارنة، لا باعتباره معيارًا للأداء.

<div id="how-it-works">
  ## آلية العمل
</div>

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

1. شغّل الاستعلام الأصلي لتحديد قياسات خط الأساس.
2. احتفظ بـ `GROUP BY`، واستبدل الحسابات التجميعية في الاستعلام بـ `count`، وأزل العمليات اللاحقة، مثل الفرز وتنسيق المخرجات.
3. أزل التجميع وشغّل `count` دون تجميع لتقدير مقدار العمل المتبقي من الفحص والتصفية وأي عمليات ربط.

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

<Note>
  هذه الفروق تقديرات تشخيصية وليست قياسات دقيقة لمراحل تنفيذ ClickHouse. قد يؤدي تغيير الاستعلام إلى تغيير خطة تنفيذه، والأعمدة المقروءة، والبيانات المنقولة بين المراحل. استخدم النتائج لصياغة فرضية، ثم تحقّق منها باستخدام سجلات الاستعلامات و[`EXPLAIN`](/docs/ar/guides/clickhouse/performance-and-monitoring/diagnose-slow-queries#explain-statement).
</Note>

<div id="establish-a-repeatable-baseline">
  ## وضع خط أساس قابل للتكرار
</div>

استخدم الممارسات التالية لجعل القياسات قابلة للمقارنة:

* أبقِ عبارات `FROM` و`JOIN` و`PREWHERE` و`WHERE` دون تغيير، لضمان استخدام البيانات والنطاق الزمني نفسيهما في كل مقارنة.
* شغّل كل إصدار من الاستعلام عدة مرات تحت حمل نظام مماثل.
* حافظ على اتساق ظروف التخزين المؤقت. إما شغّل كل إصدار من الاستعلام قبل تسجيل القياسات، أو عطّل الذواكر المؤقتة المدرجة أدناه. لا تقارن بين عمليات التشغيل المخزنة مؤقتًا وغير المخزنة مؤقتًا.
* سجّل مدةً ممثلة، مثل الوسيط لعمليات التشغيل المتكررة بعد أي عمليات إحماء، بدلًا من الاعتماد على أسرع نتيجة أو أبطئها.
* غيّر متغيرًا واحدًا في كل مرة لكي تتمكن من ربط فرق الأداء بتغيير محدد.

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

```sql theme={null}
SET enable_filesystem_cache = 0;
SET use_query_cache = 0;
SET use_query_condition_cache = 0;
SET optimize_use_implicit_projections = 0;
```

<Note>
  تنطبق عبارات `SET` هذه على الجلسة الحالية فقط. نفّذ جميع استعلامات المقارنة ضمن هذه الجلسة، أو طبّق الإعدادات نفسها على كل عملية تشغيل. لا يؤدي إعداد ذاكرة التخزين المؤقت لنظام الملفات إلى تعطيل ذاكرة الصفحات المؤقتة في نظام التشغيل أو جميع [ذواكر ClickHouse المؤقتة](/docs/ar/concepts/features/performance/caches/caches). عند الانتهاء، أغلق الجلسة المخصصة أو أعد كل إعداد إلى قيمته السابقة.
</Note>

يجمع سير العمل بين عمليات تشغيل استعلامات مضبوطة وقياسات من سجل الاستعلامات:

<Image img="https://mintcdn.com/private-7c7dfe99/fc_oxFgK6Bxv68B9/images/guides/best-practices/query_optimization_diagram_1.webp?fit=max&auto=format&n=fc_oxFgK6Bxv68B9&q=85&s=e10509e2b5504bb502dc0059304d4afc" size="lg" alt="سير عمل لتحديد الاستعلامات المرشحة في سجلات الاستعلامات واختبار التغييرات بمعزل عن غيرها" width="1928" height="1082" data-path="images/guides/best-practices/query_optimization_diagram_1.webp" />

اجمع القياسات لكل عملية تشغيل كما يلي:

1. عيّن معرّف استعلام فريدًا لكل عملية تشغيل، أو سجّل المعرّف الذي تنشئه واجهة الاستعلام. على سبيل المثال، سمِّ عمليات التشغيل المتكررة: `bottleneck-a-1` و`bottleneck-a-2` و`bottleneck-a-3`. عند استخدام `clickhouse-client`، مرّر `--query_id your-query-id` عند تنفيذ استعلام.

2. نفّذ كل استعلام مقارنة عدة مرات في الظروف نفسها. افصل عمليات تشغيل الإحماء عن عمليات التشغيل المقاسة.

3. أفرغ سجل الاستعلامات قبل البحث عن الاستعلامات المكتملة مؤخرًا:

   ```sql theme={null}
   SYSTEM FLUSH LOGS;
   ```

   إذا لم تتمكن من تشغيل `SYSTEM FLUSH LOGS`، فانتظر حتى يُفرغ سجل الاستعلامات تلقائيًا، ثم أعد محاولة البحث. إذا لم يظهر السجل مطلقًا، فتحقق من تمكين تسجيل الاستعلامات، ومن قدرتك على قراءة `system.query_log`، ومن أنك تستعلم عن العقدة التي نفّذت الاستعلام.

4. ابحث عن السجل المكتمل لكل معرّف استعلام. يسجل `system.query_log` حدثَي `QueryStart` و`QueryFinish` لكل استعلام مكتمل. رشّح حسب `QueryFinish`، الذي يحتوي على المدة النهائية والصفوف والبايتات المقروءة وذروة استخدام الذاكرة:

   ```sql theme={null}
   SELECT
       query_id,
       query_duration_ms,
       read_rows,
       read_bytes,
       memory_usage
   FROM system.query_log
   WHERE type = 'QueryFinish'
     AND query_id = 'your-query-id'
   ORDER BY event_time_microseconds DESC
   LIMIT 1;
   ```

5. لكل إصدار من الاستعلام، استخدم المدة الوسيطة لعمليات التشغيل المقاسة. سجّل `read_rows` و`read_bytes` وذروة استخدام الذاكرة من عملية التشغيل الأقرب إلى هذا الوسيط، حتى تظل القياسات مرتبطة بعملية تشغيل فعلية.

<Note>
  بالنسبة إلى الاستعلامات الموزعة، لا تمثل `memory_usage` في سجل `QueryFinish` الخاص بالاستعلام البادئ ذروة على مستوى المجموعة. استخدم `initial_query_id` لفحص سجلات `QueryFinish` الفرعية على العقد المشاركة.
</Note>

استخدم جدولًا مثل التالي لتنظيم القياسات التمثيلية. راجع [`system.query_log`](/docs/ar/reference/system-tables/query_log) لمزيد من المعلومات عن حقوله وإعداداته.

<Tabs>
  <Tab title="جدول">
    | التشغيل | إصدار الاستعلام   | المدة التمثيلية | `read_rows` | `read_bytes` | ذروة استخدام الذاكرة |
    | ------- | ----------------- | --------------- | ----------- | ------------ | -------------------- |
    | A       | الاستعلام الأصلي  |                 |             |              |                      |
    | B       | `count` مجمّع     |                 |             |              |                      |
    | C       | `count` غير مجمّع |                 |             |              |                      |
  </Tab>

  <Tab title="CSV">
    ```csv title="query-comparison.csv" theme={null}
    Run,Query version,Representative duration,read_rows,read_bytes,Peak memory
    A,Original query,,,,
    B,Grouped count,,,,
    C,Ungrouped count,,,,
    ```
  </Tab>
</Tabs>

<div id="run-progressively-simpler-queries">
  ## نفِّذ استعلامات أبسط تدريجيًا
</div>

لتوضيح المقارنات الثلاث، يستخدم المثال [عبء العمل المجمّع حسب نطاق زمني](/docs/ar/guides/clickhouse/performance-and-monitoring/query-optimization-example#date-range-aggregation). يمكنك تطبيق هذه الطريقة على استعلام آخر من دون اتباع المثال خطوةً بخطوة. إذا لم يتضمن الاستعلام `GROUP BY`، فتجاوز التشغيل B كما هو موضح أدناه.

<Steps>
  <Step title="التشغيل A: قياس الاستعلام الأصلي" id="run-a-measure-the-original-query">
    نفِّذ الاستعلام كاملًا من دون تغيير عوامل التصفية أو التجميع أو التعبيرات التجميعية أو الفرز أو المخرجات. يحدد ذلك مدة خط الأساس، وعدد الصفوف والبايتات المقروءة، وذروة استخدام الذاكرة.

    يجمع هذا الاستعلام الرحلات حسب نوع الدفع ويحسب عدة قيم تجميعية:

    ```sql theme={null}
    SELECT
        payment_type,
        count() AS trip_count,
        formatReadableQuantity(sum(trip_distance)) AS total_distance,
        avg(total_amount) AS total_amount_avg,
        avg(tip_amount) AS tip_amount_avg
    FROM nyc_taxi.trips_small_inferred
    WHERE pickup_datetime >= '2009-01-01'
      AND pickup_datetime < '2009-04-01'
    GROUP BY payment_type
    ORDER BY trip_count DESC;
    ```

    سجّل قياسات الاستعلام باعتبارها التشغيل A.
  </Step>

  <Step title="التشغيل B: الاحتفاظ بالتجميع مع count" id="run-b-retain-grouping-with-count">
    احتفظ بعبارات `FROM` و`JOIN` و`PREWHERE` و`WHERE` ومفاتيح التجميع في الاستعلام. استبدل تعبيراته التجميعية بـ `count` مجمّع. أزل المعالجة التي تلي التجميع، بما في ذلك الفرز الأصلي وتعبيرات المخرجات.

    ```sql theme={null}
    SELECT
        payment_type,
        count() AS trip_count
    FROM nyc_taxi.trips_small_inferred
    WHERE pickup_datetime >= '2009-01-01'
      AND pickup_datetime < '2009-04-01'
    GROUP BY payment_type;
    ```

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

    إذا لم يتضمن الاستعلام الأصلي `GROUP BY`، فلا توجد مرحلة تجميع لعزلها. تجاوز التشغيل B وقارن الاستعلام الأصلي مباشرةً بالتشغيل C.
  </Step>

  <Step title="التشغيل C: إزالة التجميع" id="run-c-remove-grouping">
    أزل `GROUP BY` وأرجع قيمة `count` واحدة. أبقِ عبارات `FROM` و`JOIN` و`PREWHERE` و`WHERE` من دون تغيير كي تكون المعالجة المتبقية قابلة للمقارنة.

    ```sql theme={null}
    SELECT count()
    FROM nyc_taxi.trips_small_inferred
    WHERE pickup_datetime >= '2009-01-01'
      AND pickup_datetime < '2009-04-01';
    ```

    يوفر التشغيل C خط أساس للعمليات التي تحتفظ بها خطة تنفيذه، وليس قياسًا معزولًا للفحص أو التصفية. قارنه بالتشغيل B لتقدير إسهام التجميع. وقارن أيضًا `read_bytes`، لأن إزالة مفتاح التجميع قد تقلل عدد الأعمدة المقروءة. توضح قيمة `count` المُعادة عدد الصفوف التي تصل إلى التجميع بعد عوامل التصفية وعمليات الربط المحتفَظ بها.

    قبل تفسير نتائج التشغيل C، تأكد من أن خطة تنفيذه تقرأ مصدر البيانات المقصود وتطبق عوامل التصفية المحتفَظ بها. قد يغيّر إسقاط أو `count` يعتمد على البيانات الوصفية طبيعة العمل المنفذ. للحصول على خط أساس قائم على الفحص، عطّل التحسين الظاهر في الخطة في عمليات التشغيل الثلاثة جميعها: استخدم `optimize_use_implicit_projections = 0` لإسقاط ضمني، أو `optimize_use_projections = 0` لإسقاط صريح، أو `optimize_trivial_count_query = 0` لـ `count` غير مقيّد يُستخرج من البيانات الوصفية للجدول.

    إذا ظل التشغيل C بطيئًا، فتحقق من العمليات التي يحتفظ بها، بدءًا بالفحص والتصفية. استخدم سجلات الاستعلامات و`EXPLAIN` للتحقق من عنق الزجاجة المشتبه به قبل تغيير الاستعلام.
  </Step>
</Steps>

<div id="interpret-the-differences">
  ## تفسير الفروقات
</div>

قارن مددًا ممثّلة من عمليات تشغيل متكررة بدلًا من طرح توقيتين منفردين. تشير الفروقات الكبيرة والمتسقة إلى مواضع التحقيق التالية:

| الملاحظة                          | الاختناقات المحتملة                                                                        | التحقيق التالي                                                                                                                                                                         |
| --------------------------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| التشغيل A أبطأ بكثير من التشغيل B | تعبيرات التجميع، والفرز، وأعمال أخرى بعد التجميع، أو قراءة أعمدة إضافية                    | افحص دوال التجميع المكلفة والتعبيرات و`ORDER BY` و`read_bytes` وذروة استخدام الذاكرة                                                                                                   |
| التشغيل B أبطأ بكثير من التشغيل C | التجميع، أو عدد العناصر المميزة للمجموعات، أو قراءة مفاتيح التجميع                         | افحص مفاتيح التجميع، وعدد المجموعات، و`read_bytes`، وذروة استخدام الذاكرة                                                                                                              |
| يظل التشغيل C بطيئًا              | الفحص، أو التصفية، أو عمليات الربط، أو عملية أخرى يحتفظ بها التشغيل C                      | افحص الصفوف والبايتات المقروءة، واستخدام المفتاح الأساسي، وفهارس تخطي البيانات، وخطة التنفيذ؛ ثم تحقّق من الاختناق المشتبه به                                                          |
| للعمليات الثلاث مدد متشابهة       | قد يكون مصدر زمن الاستجابة مشتركًا بين الإصدارات الثلاثة، أو ربما غيّر التبسيط خطة التنفيذ | قارن `read_rows` و`read_bytes` وذروة استخدام الذاكرة بين عمليات التشغيل. إذا كانت متشابهة أيضًا، فحقّق في العمليات التي يحتفظ بها التشغيل C. وإلا، فقارن خطط التنفيذ بحثًا عن الفروقات |

<div id="compare-rows-read-with-count-result">
  ### قارن الصفوف المقروءة بنتيجة count
</div>

قارن قيمة `read_rows` للتشغيل C بالقيمة التي تُرجعها `count`. على سبيل المثال، إذا كانت `read_rows` تساوي 100 مليون وأرجعت `count` مليونًا واحدًا، فهذا يعني أن ClickHouse فحص نحو 100 صف مصدر لكل صف تم عده. يشير ذلك إلى أن عامل التصفية استبعد معظم الصفوف المقروءة من الجدول، لكنه لا يوضح السبب. هذه النسبة مخصصة لعمليات الفحص البسيطة لجدول واحد. أما في الاستعلامات التي تتضمن مصادر بيانات متعددة أو إسقاطات، ففسّر `read_rows` باستخدام خطة التنفيذ بدلًا من ذلك.

في ClickHouse 25.9 والإصدارات الأحدث، عطّل ذاكرة التخزين المؤقت لشرط الاستعلام والتطبيق الديناميكي لفهارس تخطي البيانات قبل فحص استخدام الفهارس:

```sql theme={null}
SET use_query_condition_cache = 0;
SET use_skip_indexes_on_data_read = 0;
```

ثم استخدم [`EXPLAIN indexes = 1`](/docs/ar/guides/clickhouse/performance-and-monitoring/diagnose-slow-queries#explain-statement) لمعرفة الفهارس التي استخدمها ClickHouse، وعدد الأجزاء والحبيبات التي استبعدها كل فهرس. إذا اختار ClickHouse حبيبات أكثر من المتوقع، فتحقق مما إذا كانت عوامل التصفية تتوافق مع مفتاح ترتيب الجدول، وما إذا كان استبعاد الأقسام أو فهرس تخطي البيانات قد يستبعد مزيدًا من الحبيبات. إذا لم تتضمن الخطة قسم `Indexes`، فهذا يعني أن `EXPLAIN` لم يُظهر استبعاد الفهارس لهذا الاستعلام. أما الاستعلام التحليلي الذي يفحص الجدول بأكمله، فمن المتوقع أن يقرأ معظم بيانات الجدول.

<div id="validate-the-suspected-bottleneck">
  ## تحقّق من عنق الزجاجة المُشتبه به
</div>

بعد أن تشير المقارنة إلى وجود عنق زجاجة محتمل، تحقّق منه قبل تغيير المخطط أو الاستعلام. استخدم الأدلة المناسبة لمصدر زمن الاستجابة المُشتبه به:

* إذا كان عنق الزجاجة في الفحص أو التصفية، فاستخدم `EXPLAIN indexes = 1` مع الإعدادات الموضحة أعلاه لمعرفة الفهارس التي يستخدمها ClickHouse، وعدد الأجزاء والحبيبات التي يستبعدها كل فهرس. تحقّق مما إذا كانت الخطة تستخدم إسقاطًا ضمنيًا بدلًا من الفحص المتوقع.
* إذا كان عنق الزجاجة في التجميع حسب المجموعات أو التجميع، فافحص أحداث ملف تعريف الاستعلام ذات الصلة وذروة استخدام الذاكرة.
* إذا ظل التشغيل C بطيئًا ويحتوي على عمليات ربط، فقارنه باستعلام تشخيصي يزيل عملية ربط واحدة في كل مرة. يشير الانخفاض الكبير في المدة إلى أن عملية الربط المُزالة تسهم بقدر كبير من العمل. ولأن إزالة عملية ربط تغيّر معنى الاستعلام، فاستخدم هذه المقارنة لعزل التوقيت فقط، وفسّر التغييرات في عدد الصفوف بشكل منفصل.
* إذا كان عنق الزجاجة في عملية أخرى يحتفظ بها التشغيل C، فافحص خطة التنفيذ وأحداث ملف تعريف الاستعلام ذات الصلة.

راجع [دليل تشخيص الاستعلامات البطيئة](/docs/ar/guides/clickhouse/performance-and-monitoring/diagnose-slow-queries#explain-statement) للاطلاع على تفاصيل معلومات الفهرس التي يعرضها `EXPLAIN`. طبّق تغييرًا مستهدفًا واحدًا، ثم كرر عمليات التشغيل A وB وC في الظروف نفسها. تأكّد من أن التغيير قلّل العمل المستهدف ولم ينقل عنق الزجاجة إلى موضع آخر.

<div id="next-steps">
  ## الخطوات التالية
</div>

تابع إلى [أساليب التحسين](/docs/ar/guides/clickhouse/performance-and-monitoring/optimization-approaches) لمطابقة عنق الزجاجة المُحتمل مع تغيير مستهدف واحد أو أكثر.
