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

# أقسام الجدول

> ما هي أقسام الجدول في ClickHouse

export const RunnableCode = ({children, run = false, showStats = true}) => {
  const [results, setResults] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [showResults, setShowResults] = useState(false);
  const [stats, setStats] = useState(null);
  const [isDark, setIsDark] = useState(false);
  const [hoveredRow, setHoveredRow] = useState(-1);
  const codeRef = useRef(null);
  useEffect(() => {
    if (typeof window !== "undefined") {
      const check = () => setIsDark(document.documentElement.classList.contains("dark"));
      check();
      const observer = new MutationObserver(check);
      observer.observe(document.documentElement, {
        attributes: true,
        attributeFilter: ["class"]
      });
      return () => observer.disconnect();
    }
  }, []);
  useEffect(() => {
    if (codeRef.current) {
      const block = codeRef.current.querySelector(".code-block");
      if (block) {
        block.style.marginBottom = "0";
        block.style.marginTop = "0";
        block.style.borderBottomLeftRadius = "0";
        block.style.borderBottomRightRadius = "0";
      }
    }
  });
  const getSqlText = () => {
    if (!codeRef.current) return "";
    const code = codeRef.current.querySelector("code");
    return (code || codeRef.current).textContent.trim();
  };
  const executeQuery = async () => {
    const sql = getSqlText();
    if (!sql) return;
    setLoading(true);
    setError(null);
    setResults(null);
    setShowResults(true);
    try {
      const cleanQuery = sql.replace(/;$/, "").trim();
      const params = new URLSearchParams({
        query: cleanQuery,
        default_format: "JSONCompact",
        result_overflow_mode: "break",
        read_overflow_mode: "break",
        allow_experimental_analyzer: "1"
      });
      const res = await fetch(`https://sql-clickhouse.clickhouse.com/?${params.toString()}`, {
        method: "POST",
        headers: {
          Authorization: `Basic ${btoa(`demo:`)}`
        }
      });
      const text = await res.text();
      if (!res.ok) {
        setError(text || `HTTP ${res.status}`);
        setLoading(false);
        return;
      }
      const json = JSON.parse(text);
      setResults(json);
      setStats(json.statistics || null);
    } catch (err) {
      setError(err.message || "فشل تنفيذ الاستعلام");
    }
    setLoading(false);
  };
  useEffect(() => {
    if (run) executeQuery();
  }, []);
  const formatRows = n => {
    if (n >= 1e9) return `${(n / 1e9).toFixed(1)}B`;
    if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
    if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
    return String(n);
  };
  const formatBytes = b => {
    if (b >= 1e9) return `${(b / 1e9).toFixed(2)} GB`;
    if (b >= 1e6) return `${(b / 1e6).toFixed(2)} MB`;
    if (b >= 1e3) return `${(b / 1e3).toFixed(2)} KB`;
    return `${b} B`;
  };
  const isNumericType = type => {
    return (/^(UInt|Int|Float|Decimal)/).test(type);
  };
  const isHyperlink = value => {
    return typeof value === "string" && (/^https?:\/\//).test(value);
  };
  const computeColumnExtremes = (meta, data) => {
    const extremes = {};
    for (let i = 0; i < meta.length; i++) {
      if (isNumericType(meta[i].type)) {
        let min = Infinity, max = -Infinity;
        for (const row of data) {
          const v = Number(row[i]);
          if (!isNaN(v)) {
            if (v < min) min = v;
            if (v > max) max = v;
          }
        }
        if (max > -Infinity) {
          extremes[i] = {
            min,
            max
          };
        }
      }
    }
    return extremes;
  };
  const computeColumnWidths = (meta, data) => {
    const lengths = meta.map((col, i) => {
      const headerLen = col.name.length + col.type.length + 1;
      let maxData = 0;
      for (const row of data) {
        const v = row[i];
        const len = v === null ? 4 : String(v).length;
        if (len > maxData) maxData = len;
      }
      return Math.max(headerLen, maxData);
    });
    const total = lengths.reduce((s, l) => s + l, 0);
    return lengths.map(l => `${(l / total * 100).toFixed(1)}%`);
  };
  const copyResultsAsTSV = () => {
    if (!results || !results.meta || !results.data) return;
    const header = results.meta.map(col => col.name).join("\t");
    const rows = results.data.map(row => row.map(cell => cell === null ? "NULL" : String(cell)).join("\t"));
    const tsv = [header, ...rows].join("\n");
    navigator.clipboard.writeText(tsv);
  };
  const borderColor = isDark ? "rgba(255,255,255,0.15)" : "#e5e7eb";
  const bgColor = isDark ? "rgba(255,255,255,0.05)" : "#f9fafb";
  const headerBg = isDark ? "#2a2a2a" : "#f3f4f6";
  const textColor = isDark ? "#e5e7eb" : "#1f2937";
  const mutedColor = isDark ? "#d1d5db" : "#6b7280";
  const accentColor = isDark ? "#FAFF69" : "#323232";
  const accentTextColor = isDark ? "#000" : "#fff";
  const barColor = isDark ? "#35372f" : "#d2d2d2";
  const cellBg = isDark ? "#1f201b" : "#ffffff";
  const cellBgHover = isDark ? "lch(15.8 0 0)" : "#f0f0f0";
  const extremes = results && results.meta && results.data ? computeColumnExtremes(results.meta, results.data) : {};
  const colWidths = results && results.meta && results.data ? computeColumnWidths(results.meta, results.data) : [];
  const getCellBarStyle = (cell, ci, ri) => {
    if (cell === null) return null;
    const colMeta = results.meta[ci];
    if (!isNumericType(colMeta.type) || !extremes[ci] || results.data.length <= 1 || extremes[ci].max <= 0) return null;
    const ratio = 100 * Number(cell) / extremes[ci].max;
    const bg = ri === hoveredRow ? cellBgHover : cellBg;
    return {
      background: `linear-gradient(to right, ${barColor} 0%, ${barColor} ${ratio}%, ${bg} ${ratio}%, ${bg} 100%)`
    };
  };
  const renderCell = (cell, ci) => {
    if (cell === null) {
      return <span style={{
        color: mutedColor,
        fontStyle: "italic"
      }}>NULL</span>;
    }
    const value = String(cell);
    if (isHyperlink(value)) {
      return <a href={value} target="_blank" rel="noopener noreferrer" style={{
        color: accentColor,
        textDecoration: "underline",
        cursor: "pointer"
      }}>
          {value}
        </a>;
    }
    return value;
  };
  return <div className="not-prose" style={{
    margin: "1rem 0",
    width: "100%",
    boxSizing: "border-box",
    contain: "inline-size"
  }}>
      {}
      <div>
        <div ref={codeRef}>{children}</div>

        {}
        <div style={{
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
    padding: "6px 12px",
    backgroundColor: headerBg,
    borderWidth: "0 1px 1px 1px",
    borderStyle: "solid",
    borderColor: isDark ? "rgba(255,255,255,0.1)" : "rgba(11,11,11,0.1)",
    borderRadius: "0 0 4px 4px"
  }}>
          <div style={{
    display: "flex",
    alignItems: "center",
    gap: "12px"
  }}>
            {results && <button onClick={() => setShowResults(!showResults)} style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    color: mutedColor,
    fontSize: "12px",
    padding: "2px 4px"
  }}>
                {showResults ? "▼ إخفاء النتائج" : "▶ إظهار النتائج"}
              </button>}
            {showStats && stats && <span style={{
    fontSize: "11px",
    color: mutedColor,
    fontStyle: "italic"
  }}>
                تمت قراءة {formatRows(stats.rows_read)} صفوف، {formatBytes(stats.bytes_read)} في {stats.elapsed.toFixed(3)}ث
              </span>}
          </div>
          <button onClick={() => executeQuery()} disabled={loading} style={{
    display: "flex",
    alignItems: "center",
    gap: "6px",
    padding: "4px 14px",
    borderRadius: "4px",
    border: "none",
    cursor: loading ? "wait" : "pointer",
    backgroundColor: accentColor,
    color: accentTextColor,
    fontSize: "12px",
    fontWeight: 600
  }}>
            {loading ? <span>جارٍ التنفيذ...</span> : <>
                <span style={{
    fontSize: "10px"
  }}>▶</span>
                <span>تشغيل</span>
              </>}
          </button>
        </div>
      </div>

      {}
      {showResults && <div className="not-prose" style={{
    marginTop: "8px",
    maxHeight: "350px",
    overflow: "auto",
    border: `1px solid ${borderColor}`,
    borderRadius: "4px"
  }}>
          <div>
            {loading && <div style={{
    padding: "24px",
    textAlign: "center",
    color: mutedColor
  }}>جارٍ تنفيذ الاستعلام...</div>}

            {error && <div style={{
    padding: "12px 16px",
    color: "#ef4444",
    backgroundColor: isDark ? "rgba(239,68,68,0.1)" : "#fef2f2",
    fontSize: "13px",
    fontFamily: "monospace",
    whiteSpace: "pre-wrap"
  }}>
                {error}
              </div>}

            {results && results.meta && results.data && <div style={{
    display: "grid",
    gridTemplateColumns: colWidths.join(" "),
    width: "100%",
    fontSize: "13px",
    fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace'
  }}>
                {results.meta.map((col, i) => <div key={`h-${i}`} style={{
    position: "sticky",
    top: 0,
    zIndex: 1,
    padding: "6px 12px",
    textAlign: isNumericType(col.type) && results.meta.length > 1 ? "right" : "left",
    backgroundColor: headerBg,
    borderBottom: `1px solid ${borderColor}`,
    color: textColor,
    fontWeight: 600,
    fontSize: "12px",
    whiteSpace: "nowrap",
    overflow: "hidden",
    textOverflow: "ellipsis"
  }}>
                    {col.name}
                    <span style={{
    color: mutedColor,
    fontWeight: 400,
    marginLeft: "4px",
    fontSize: "10px"
  }}>{col.type}</span>
                  </div>)}
                {results.data.map((row, ri) => row.map((cell, ci) => <div key={`${ri}-${ci}`} onMouseEnter={() => setHoveredRow(ri)} onMouseLeave={() => setHoveredRow(-1)} style={{
    padding: "4px 12px",
    color: textColor,
    whiteSpace: "nowrap",
    overflow: "hidden",
    textOverflow: "ellipsis",
    textAlign: isNumericType(results.meta[ci].type) && results.meta.length > 1 ? "right" : "left",
    borderBottom: `1px solid ${borderColor}`,
    backgroundColor: ri === hoveredRow ? cellBgHover : ri % 2 === 0 ? "transparent" : bgColor,
    transition: "background-color 0.1s",
    ...getCellBarStyle(cell, ci, ri)
  }}>
                      {renderCell(cell, ci)}
                    </div>))}
              </div>}

            {results && results.data && <div style={{
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
    padding: "4px 12px",
    fontSize: "11px",
    color: mutedColor,
    borderTop: `1px solid ${borderColor}`,
    backgroundColor: headerBg
  }}>
                <span>
                  {results.rows} {results.rows !== 1 ? "صفوف" : "صف"}
                </span>
                <button onClick={copyResultsAsTSV} style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    color: mutedColor,
    fontSize: "11px",
    padding: "2px 6px",
    borderRadius: "3px"
  }} onMouseEnter={e => e.target.style.color = textColor} onMouseLeave={e => e.target.style.color = mutedColor}>
                  ⧉ نسخ TSV
                </button>
              </div>}
          </div>
        </div>}
    </div>;
};

export const Image = ({img, alt, size}) => {
  return <Frame>
      <img src={img} alt={alt} />
    </Frame>;
};

<div id="what-are-table-partitions-in-clickhouse">
  ## ما هي أقسام الجدول في ClickHouse؟
</div>

<br />

تُجمِّع أقسام الجدول [أجزاء البيانات](/ar/concepts/core-concepts/parts) الخاصة بجدول ضمن [عائلة محركات MergeTree](/ar/reference/engines/table-engines/mergetree-family/index) في وحدات منطقية منظَّمة، وهي طريقة لتنظيم البيانات بما يجعلها ذات دلالة مفاهيمية ومتوافقة مع معايير محددة، مثل النطاقات الزمنية أو الفئات أو السمات الرئيسية الأخرى. وتُسهِّل هذه الوحدات المنطقية إدارة البيانات والاستعلام عنها وتحسينها.

<div id="partition-by">
  ### PARTITION BY
</div>

يمكن تفعيل التقسيم عند تعريف الجدول مبدئيًا عبر [عبارة PARTITION BY](/ar/reference/engines/table-engines/mergetree-family/custom-partitioning-key). ويمكن أن تتضمن هذه العبارة تعبير SQL على أيٍّ من الأعمدة، بحيث تحدد نتائج هذا التعبير القسم الذي ينتمي إليه الصف.

ولتوضيح ذلك، نقوم [بتعديل](https://sql.clickhouse.com/?query=U0hPVyBDUkVBVEUgVEFCTEUgdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQ\&run_query=true\&tab=results) جدول المثال في [ما هي أجزاء الجدول](/ar/concepts/core-concepts/parts) بإضافة عبارة `PARTITION BY toStartOfMonth(date)`، التي تنظّم أجزاء بيانات الجدول بحسب أشهر مبيعات العقارات:

```sql theme={null}
CREATE TABLE uk.uk_price_paid_simple_partitioned
(
    date Date,
    town LowCardinality(String),
    street LowCardinality(String),
    price UInt32
)
ENGINE = MergeTree
ORDER BY (town, street)
PARTITION BY toStartOfMonth(date);
```

يمكنك [الاستعلام عن هذا الجدول](https://sql.clickhouse.com/?query=U0VMRUNUICogRlJPTSB1ay51a19wcmljZV9wYWlkX3NpbXBsZV9wYXJ0aXRpb25lZA\&run_query=true\&tab=results) في ClickHouse SQL Playground التابع لنا.

<div id="structure-on-disk">
  ### البنية على القرص
</div>

عند إدراج مجموعة من الصفوف في الجدول، لا ينشئ ClickHouse جزء بيانات واحدًا يحتوي على جميع الصفوف المُدرجة (على [الأقل](/ar/reference/settings/session-settings#max_insert_block_size))، كما هو موضح [هنا](/ar/concepts/core-concepts/parts)، بل ينشئ جزء بيانات جديدًا لكل قيمة فريدة لمفتاح القسم بين الصفوف المُدرجة:

<Image img="https://mintcdn.com/private-7c7dfe99-mintlify-fbfa8bee/rF8ZX2ZZNpnwXrqH/images/managing-data/core-concepts/partitions.png?fit=max&auto=format&n=rF8ZX2ZZNpnwXrqH&q=85&s=697116401d8f11285518e0b1ace63ffd" size="lg" alt="معالجة INSERT" width="3324" height="2270" data-path="images/managing-data/core-concepts/partitions.png" />

<br />

يقوم ClickHouse server أولًا بتقسيم الصفوف في مثال الإدراج، الذي يتضمن 4 صفوف كما هو موضح في المخطط أعلاه، وفقًا لقيمة مفتاح القسم `toStartOfMonth(date)`.
ثم تُعالَج الصفوف، لكل قسم تم تحديده، [كالمعتاد](/ar/concepts/core-concepts/parts) من خلال تنفيذ عدة خطوات متسلسلة (① الفرز، ② التقسيم إلى أعمدة، ③ الضغط، ④ الكتابة إلى القرص).

لاحظ أنه عند تمكين التقسيم، ينشئ ClickHouse تلقائيًا [فهارس MinMax](https://github.com/ClickHouse/ClickHouse/blob/dacc8ebb0dac5bbfce5a7541e7fc70f26f7d5065/src/Storages/MergeTree/IMergeTreeDataPart.h#L341) لكل جزء بيانات. وهي ببساطة ملفات لكل عمود في الجدول مستخدم في تعبير مفتاح القسم، وتحتوي على القيمتين الصغرى والكبرى لذلك العمود داخل جزء البيانات.

<div id="per-partition-merges">
  ### عمليات الدمج داخل كل قسم
</div>

عند تمكين التقسيم، لا يَدمج ClickHouse [أجزاء البيانات](/ar/concepts/core-concepts/merges) إلا داخل القسم نفسه، وليس عبر الأقسام. نوضّح ذلك في مثال الجدول أعلاه:

<Image img="https://mintcdn.com/private-7c7dfe99-mintlify-fbfa8bee/rF8ZX2ZZNpnwXrqH/images/managing-data/core-concepts/merges_with_partitions.png?fit=max&auto=format&n=rF8ZX2ZZNpnwXrqH&q=85&s=8792d49d8dfa106f63224cd839ed3540" size="lg" alt="عمليات دمج الأجزاء" width="2480" height="1870" data-path="images/managing-data/core-concepts/merges_with_partitions.png" />

<br />

كما يوضّح المخطط أعلاه، لا تُدمَج الأجزاء التابعة لأقسام مختلفة مطلقًا. وإذا اخترت مفتاح تقسيم ذي عددية مرتفعة، فستتوزع الأجزاء على آلاف الأقسام، ولن تصبح مرشحة للدمج أبدًا، ما يؤدي إلى تجاوز الحدود المضبوطة مسبقًا والتسبب في ظهور الخطأ المزعج `Too many parts`. وحل هذه المشكلة بسيط: اختر مفتاح تقسيم مناسبًا ذي [عددية أقل من 1000..10000](https://github.com/ClickHouse/ClickHouse/blob/ffc5b2c56160b53cf9e5b16cfb73ba1d956f7ce4/src/Storages/MergeTree/MergeTreeDataWriter.cpp#L121).

<div id="monitoring-partitions">
  ## مراقبة الأقسام
</div>

يمكنك [الاستعلام عن](https://sql.clickhouse.com/?query=U0VMRUNUIERJU1RJTkNUIF9wYXJ0aXRpb25fdmFsdWUgQVMgcGFydGl0aW9uCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQKT1JERVIgQlkgcGFydGl0aW9uIEFTQw\&run_query=true\&tab=results) قائمة جميع الأقسام الفريدة الموجودة في جدول المثال باستخدام [العمود الافتراضي](/ar/reference/engines/table-engines/index#table_engines-virtual_columns) `_partition_value`:

<RunnableCode>
  ```sql theme={null}
  SELECT DISTINCT _partition_value AS partition
  FROM uk.uk_price_paid_simple_partitioned
  ORDER BY partition ASC;
  ```
</RunnableCode>

بدلاً من ذلك، يتتبع ClickHouse جميع الأجزاء والأقسام لكل الجداول في جدول النظام [system.parts](/ar/reference/system-tables/parts)، ويُرجع [الاستعلام](https://sql.clickhouse.com/?query=U0VMRUNUCiAgICBwYXJ0aXRpb24sCiAgICBjb3VudCgpIEFTIHBhcnRzLAogICAgc3VtKHJvd3MpIEFTIHJvd3MKRlJPTSBzeXN0ZW0ucGFydHMKV0hFUkUgKGRhdGFiYXNlID0gJ3VrJykgQU5EIChgdGFibGVgID0gJ3VrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkJykgQU5EIGFjdGl2ZQpHUk9VUCBCWSBwYXJ0aXRpb24KT1JERVIgQlkgcGFydGl0aW9uIEFTQzs\&run_query=true\&tab=results) التالي لجدول المثال أعلاه قائمةً بجميع الأقسام، بالإضافة إلى العدد الحالي من الأجزاء النشطة وإجمالي الصفوف في هذه الأجزاء لكل قسم:

<RunnableCode>
  ```sql theme={null}
  SELECT
      partition,
      count() AS parts,
      sum(rows) AS rows
  FROM system.parts
  WHERE (database = 'uk') AND (`table` = 'uk_price_paid_simple_partitioned') AND active
  GROUP BY partition
  ORDER BY partition ASC;
  ```
</RunnableCode>

<div id="what-are-table-partitions-used-for">
  ## فيما تُستخدم أقسام الجدول؟
</div>

<div id="data-management">
  ### إدارة البيانات
</div>

في ClickHouse، يُعد التقسيم بالأساس ميزة لإدارة البيانات. فمن خلال تنظيم البيانات منطقيًا استنادًا إلى تعبير التقسيم، يمكن إدارة كل قسم على حدة. على سبيل المثال، يتيح مخطط التقسيم في جدول Example أعلاه حالات استخدام لا يُحتفَظ فيها إلا ببيانات آخر 12 شهرًا في الجدول الرئيسي، مع إزالة البيانات الأقدم تلقائيًا باستخدام [قاعدة TTL](/ar/concepts/features/operations/delete/ttl) (راجع الصف الأخير المُضاف في عبارة DDL):

```sql theme={null}
CREATE TABLE uk.uk_price_paid_simple_partitioned
(
    date Date,
    town LowCardinality(String),
    street LowCardinality(String),
    price UInt32
)
ENGINE = MergeTree
PARTITION BY toStartOfMonth(date)
ORDER BY (town, street)
TTL date + INTERVAL 12 MONTH DELETE;
```

نظرًا لأن الجدول مُقسَّم باستخدام `toStartOfMonth(date)`، فستُحذف الأقسام كاملةً (وهي مجموعات من [أجزاء الجدول](/ar/concepts/core-concepts/parts)) التي تستوفي شرط TTL، مما يجعل عملية التنظيف أكثر كفاءة، [من دون الحاجة إلى إعادة كتابة الأجزاء](/ar/reference/statements/alter/index#mutations).

وبالمثل، بدلًا من حذف البيانات القديمة، يمكن نقلها تلقائيًا وبكفاءة إلى [فئة تخزين](/ar/integrations/connectors/data-ingestion/AWS/integrating-s3-with-clickhouse#storage-tiers) أقل تكلفة:

```sql theme={null}
CREATE TABLE uk.uk_price_paid_simple_partitioned
(
    date Date,
    town LowCardinality(String),
    street LowCardinality(String),
    price UInt32
)
ENGINE = MergeTree
PARTITION BY toStartOfMonth(date)
ORDER BY (town, street)
TTL date + INTERVAL 12 MONTH TO VOLUME 'slow_but_cheap';
```

<div id="query-optimization">
  ### تحسين الاستعلام
</div>

يمكن أن تساعد الأقسام في تحسين أداء الاستعلام، لكن ذلك يعتمد بدرجة كبيرة على أنماط الوصول. فإذا كانت الاستعلامات تستهدف عددًا قليلًا فقط من الأقسام (ومن الأفضل أن يكون قسمًا واحدًا)، فقد يتحسن الأداء. ويكون هذا مفيدًا عادةً فقط إذا لم يكن مفتاح التقسيم جزءًا من المفتاح الأساسي وكنت تُجري تصفية بناءً عليه، كما هو موضح في الاستعلام المثال أدناه.

<RunnableCode>
  ```sql theme={null}
  SELECT MAX(price) AS highest_price
  FROM uk.uk_price_paid_simple_partitioned
  WHERE date >= '2020-12-01'
    AND date <= '2020-12-31'
    AND town = 'LONDON';
  ```
</RunnableCode>

يُنفَّذ هذا الاستعلام على جدول المثال المذكور أعلاه، ويقوم [بحساب](https://sql.clickhouse.com/?query=U0VMRUNUIE1BWChwcmljZSkgQVMgaGlnaGVzdF9wcmljZQpGUk9NIHVrLnVrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkCldIRVJFIGRhdGUgPj0gJzIwMjAtMTItMDEnCiAgQU5EIGRhdGUgPD0gJzIwMjAtMTItMzEnCiAgQU5EIHRvd24gPSAnTE9ORE9OJzs\&run_query=true\&tab=results) أعلى سعر لجميع العقارات المبيعة في لندن خلال ديسمبر 2020، وذلك عبر التصفية على كلٍّ من عمود (`date`) المُستخدَم في مفتاح تقسيم الجدول وعمود (`town`) المُستخدَم في المفتاح الأساسي للجدول (مع العلم أن `date` ليس جزءًا من المفتاح الأساسي).

يعالج ClickHouse هذا الاستعلام من خلال تطبيق سلسلة من تقنيات تقليم البيانات لتجنّب فحص البيانات غير ذات الصلة:

<Image img="https://mintcdn.com/private-7c7dfe99-mintlify-fbfa8bee/rF8ZX2ZZNpnwXrqH/images/managing-data/core-concepts/partition-pruning.png?fit=max&auto=format&n=rF8ZX2ZZNpnwXrqH&q=85&s=4b3b108e73064db0364e3411683a706c" size="lg" alt="PART MERGES 2" width="2478" height="1886" data-path="images/managing-data/core-concepts/partition-pruning.png" />

<br />

① **تقليم الأقسام**: تُستخدَم [فهارس MinMax](/ar/concepts/core-concepts/partitions#what-are-table-partitions-in-clickhouse) لتجاهل أقسام كاملة (مجموعات من الأجزاء) لا يمكن منطقيًا أن تطابق عامل التصفية في الاستعلام على الأعمدة المستخدمة في مفتاح تقسيم الجدول.

② **تقليم الحبيبات**: بالنسبة إلى أجزاء البيانات المتبقية بعد الخطوة ①، يُستخدَم [الفهرس الأساسي](/ar/guides/clickhouse/data-modelling/sparse-primary-indexes) لتجاهل جميع [الحبيبات](/ar/guides/clickhouse/data-modelling/sparse-primary-indexes#data-is-organized-into-granules-for-parallel-data-processing) (كتل من الصفوف) التي لا يمكن منطقيًا أن تطابق عامل التصفية في الاستعلام على الأعمدة المستخدمة في المفتاح الأساسي للجدول.

يمكننا ملاحظة خطوات تقليم البيانات هذه من خلال [فحص](https://sql.clickhouse.com/?query=RVhQTEFJTiBpbmRleGVzID0gMQpTRUxFQ1QgTUFYKHByaWNlKSBBUyBoaWdoZXN0X3ByaWNlCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQKV0hFUkUgZGF0ZSA-PSAnMjAyMC0xMi0wMScKICBBTkQgZGF0ZSA8PSAnMjAyMC0xMi0zMScKICBBTkQgdG93biA9ICdMT05ET04nOw\&run_query=true\&tab=results) خطة تنفيذ الاستعلام الفعلية لاستعلام المثال المذكور أعلاه باستخدام عبارة [EXPLAIN](/ar/reference/statements/explain):

```sql style="fontSize:13px" theme={null}
EXPLAIN indexes = 1
SELECT MAX(price) AS highest_price
FROM uk.uk_price_paid_simple_partitioned
WHERE date >= '2020-12-01'
  AND date <= '2020-12-31'
  AND town = 'LONDON';
```

```response theme={null}
    ┌─explain──────────────────────────────────────────────────────────────────────────────────────────────────────┐
 1. │ Expression ((Project names + Projection))                                                                    │
 2. │   Aggregating                                                                                                │
 3. │     Expression (Before GROUP BY)                                                                             │
 4. │       Expression                                                                                             │
 5. │         ReadFromMergeTree (uk.uk_price_paid_simple_partitioned)                                              │
 6. │         Indexes:                                                                                             │
 7. │           MinMax                                                                                             │
 8. │             Keys:                                                                                            │
 9. │               date                                                                                           │
10. │             Condition: and((date in (-Inf, 18627]), (date in [18597, +Inf)))                                 │
11. │             Parts: 1/436                                                                                     │
12. │             Granules: 11/3257                                                                                │
13. │           Partition                                                                                          │
14. │             Keys:                                                                                            │
15. │               toStartOfMonth(date)                                                                           │
16. │             Condition: and((toStartOfMonth(date) in (-Inf, 18597]), (toStartOfMonth(date) in [18597, +Inf))) │
17. │             Parts: 1/1                                                                                       │
18. │             Granules: 11/11                                                                                  │
19. │           PrimaryKey                                                                                         │
20. │             Keys:                                                                                            │
21. │               town                                                                                           │
22. │             Condition: (town in ['LONDON', 'LONDON'])                                                        │
23. │             Parts: 1/1                                                                                       │
24. │             Granules: 1/11                                                                                   │
    └──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
```

يوضح الناتج أعلاه ما يلي:

① تقليم الأقسام: تُظهر الأسطر من 7 إلى 18 من ناتج EXPLAIN أعلاه أن ClickHouse يستخدم أولًا [MinMax index](/ar/concepts/core-concepts/partitions#what-are-table-partitions-in-clickhouse) الخاص بالحقل `date` لتحديد 11 من أصل 3257 [حبيبة](/ar/guides/clickhouse/data-modelling/sparse-primary-indexes#data-is-organized-into-granules-for-parallel-data-processing) (كتل من الصفوف) مخزَّنة في جزء بيانات نشط واحد من أصل 436 جزء بيانات نشط موجود، وتحتوي على صفوف تطابق عامل التصفية `date` الخاص بالاستعلام.

② تقليم الحبيبة: تشير الأسطر من 19 إلى 24 من ناتج EXPLAIN أعلاه إلى أن ClickHouse يستخدم بعد ذلك [الفهرس الأساسي](/ar/guides/clickhouse/data-modelling/sparse-primary-indexes) (الذي أُنشئ على الحقل `town`) لجزء البيانات الذي جرى تحديده في الخطوة ①، لتقليل عدد الحبيبات أكثر (التي تحتوي على صفوف قد تطابق أيضًا عامل التصفية `town` الخاص بالاستعلام) من 11 إلى 1. وينعكس ذلك أيضًا في ناتج ClickHouse-client الذي طبعناه أعلاه للاستعلام المُنفَّذ:

```response theme={null}
... Elapsed: 0.006 sec. Processed 8.19 thousand rows, 57.34 KB (1.36 million rows/s., 9.49 MB/s.)
Peak memory usage: 2.73 MiB.
```

ما يعني أن ClickHouse فحص وعالج granule واحدة (كتلة من [8192](/ar/reference/settings/merge-tree-settings#index_granularity) صفًا) في غضون 6 مللي ثانية لحساب نتيجة الاستعلام.

<div id="partitioning-is-primarily-a-data-management-feature">
  ### يُعد التقسيم في المقام الأول ميزة لإدارة البيانات
</div>

انتبه إلى أن تنفيذ الاستعلام عبر جميع الأقسام يكون عادةً أبطأ من تنفيذ الاستعلام نفسه على جدول غير مُقسَّم.

مع التقسيم، تتوزع البيانات عادةً على عدد أكبر من أجزاء البيانات، ما يؤدي غالبًا إلى أن يقوم ClickHouse بمسح حجم أكبر من البيانات ومعالجته.

يمكننا توضيح ذلك عبر تشغيل الاستعلام نفسه على كلٍّ من جدول المثال [ما هي أجزاء الجدول](/ar/concepts/core-concepts/parts) (من دون تمكين التقسيم)، وجدول المثال الحالي أعلاه (مع تمكين التقسيم). يحتوي الجدولان [على](https://sql.clickhouse.com/?query=U0VMRUNUCiAgICB0YWJsZSwKICAgIHN1bShyb3dzKSBBUyByb3dzCkZST00gc3lzdGVtLnBhcnRzCldIRVJFIChkYXRhYmFzZSA9ICd1aycpIEFORCAoYHRhYmxlYCBJTiBbJ3VrX3ByaWNlX3BhaWRfc2ltcGxlJywgJ3VrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkJ10pIEFORCBhY3RpdmUKR1JPVVAgQlkgdGFibGU7\&run_query=true\&tab=results) على البيانات نفسها وعدد الصفوف نفسه:

<RunnableCode>
  ```sql theme={null}
  SELECT
      table,
      sum(rows) AS rows
  FROM system.parts
  WHERE (database = 'uk') AND (table IN ['uk_price_paid_simple', 'uk_price_paid_simple_partitioned']) AND active
  GROUP BY table;
  ```
</RunnableCode>

ومع ذلك، فإن الجدول الذي فُعِّل فيه التقسيم [يحتوي على](https://sql.clickhouse.com/?query=U0VMRUNUCiAgICB0YWJsZSwKICAgIGNvdW50KCkgQVMgcGFydHMKRlJPTSBzeXN0ZW0ucGFydHMKV0hFUkUgKGRhdGFiYXNlID0gJ3VrJykgQU5EIChgdGFibGVgIElOIFsndWtfcHJpY2VfcGFpZF9zaW1wbGUnLCAndWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQnXSkgQU5EIGFjdGl2ZQpHUk9VUCBCWSB0YWJsZTs\&run_query=true\&tab=results) على عدد أكبر من [أجزاء البيانات](/ar/concepts/core-concepts/parts) النشطة، لأن ClickHouse، كما ذُكر أعلاه، لا [يدمج](/ar/concepts/core-concepts/parts) أجزاء البيانات إلا داخل الأقسام، وليس عبرها:

<RunnableCode>
  ```sql theme={null}
  SELECT
      table,
      count() AS parts
  FROM system.parts
  WHERE (database = 'uk') AND (table IN ['uk_price_paid_simple', 'uk_price_paid_simple_partitioned']) AND active
  GROUP BY table;

  ```
</RunnableCode>

كما هو موضح أعلاه، يحتوي الجدول المُقسَّم `uk_price_paid_simple_partitioned` على أكثر من 600 قسم، وبالتالي على 600 306 من أجزاء البيانات النشطة. أما جدولنا غير المُقسَّم `uk_price_paid_simple`، فقد أمكن دمج جميع أجزاء البيانات [الأولية](/ar/concepts/core-concepts/parts) فيه في جزء نشط واحد عبر عمليات الدمج في الخلفية.

عندما [نتحقق من](https://sql.clickhouse.com/?query=RVhQTEFJTiBpbmRleGVzID0gMQpTRUxFQ1QgTUFYKHByaWNlKSBBUyBoaWdoZXN0X3ByaWNlCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGVfcGFydGl0aW9uZWQKV0hFUkUgdG93biA9ICdMT05ET04nOw\&run_query=true\&tab=results) خطة التنفيذ الفعلية للاستعلام باستخدام عبارة [EXPLAIN](/ar/reference/statements/explain) لاستعلام المثال أعلاه، من دون مُرشِّح للقسم، عند تشغيله على الجدول المُقسَّم، يمكننا أن نرى في الصفين 19 و20 من المخرجات أدناه أن ClickHouse حدّد 671 من أصل 3257 [حبيبة](/ar/guides/clickhouse/data-modelling/sparse-primary-indexes#data-is-organized-into-granules-for-parallel-data-processing) موجودة (كتل من الصفوف)، موزعة على 431 من أصل 436 جزء بيانات نشط موجود، قد تحتوي على صفوف تطابق مُرشِّح الاستعلام، ولذلك سيجري محرك الاستعلام مسحها ومعالجتها:

```sql theme={null}
EXPLAIN indexes = 1
SELECT MAX(price) AS highest_price
FROM uk.uk_price_paid_simple_partitioned
WHERE town = 'LONDON';
```

```response theme={null}
    ┌─explain─────────────────────────────────────────────────────────┐
 1. │ Expression ((Project names + Projection))                       │
 2. │   Aggregating                                                   │
 3. │     Expression (Before GROUP BY)                                │
 4. │       Expression                                                │
 5. │         ReadFromMergeTree (uk.uk_price_paid_simple_partitioned) │
 6. │         Indexes:                                                │
 7. │           MinMax                                                │
 8. │             Condition: true                                     │
 9. │             Parts: 436/436                                      │
10. │             Granules: 3257/3257                                 │
11. │           Partition                                             │
12. │             Condition: true                                     │
13. │             Parts: 436/436                                      │
14. │             Granules: 3257/3257                                 │
15. │           PrimaryKey                                            │
16. │             Keys:                                               │
17. │               town                                              │
18. │             Condition: (town in ['LONDON', 'LONDON'])           │
19. │             Parts: 431/436                                      │
20. │             Granules: 671/3257                                  │
    └─────────────────────────────────────────────────────────────────┘
```

تُظهر [خطة تنفيذ الاستعلام المادية](https://sql.clickhouse.com/?query=RVhQTEFJTiBpbmRleGVzID0gMQpTRUxFQ1QgTUFYKHByaWNlKSBBUyBoaWdoZXN0X3ByaWNlCkZST00gdWsudWtfcHJpY2VfcGFpZF9zaW1wbGUKV0hFUkUgdG93biA9ICdMT05ET04nOw\&run_query=true\&tab=results) للاستعلام نفسه عند تشغيله على الجدول من دون تقسيمات، في الصفَّين 11 و12 من المخرجات أدناه، أن ClickHouse حدَّد 241 من أصل 3083 كتلة صفوف موجودة ضمن جزء البيانات النشط الوحيد في الجدول، وقد تحتوي على صفوف تطابق عامل التصفية الخاص بالاستعلام:

```sql theme={null}
EXPLAIN indexes = 1
SELECT MAX(price) AS highest_price
FROM uk.uk_price_paid_simple
WHERE town = 'LONDON';
```

```response theme={null}
    ┌─explain───────────────────────────────────────────────┐
 1. │ Expression ((Project names + Projection))             │
 2. │   Aggregating                                         │
 3. │     Expression (Before GROUP BY)                      │
 4. │       Expression                                      │
 5. │         ReadFromMergeTree (uk.uk_price_paid_simple)   │
 6. │         Indexes:                                      │
 7. │           PrimaryKey                                  │
 8. │             Keys:                                     │
 9. │               town                                    │
10. │             Condition: (town in ['LONDON', 'LONDON']) │
11. │             Parts: 1/1                                │
12. │             Granules: 241/3083                        │
    └───────────────────────────────────────────────────────┘
```

عند [تشغيل](https://sql.clickhouse.com/?query=U0VMRUNUIE1BWChwcmljZSkgQVMgaGlnaGVzdF9wcmljZQpGUk9NIHVrLnVrX3ByaWNlX3BhaWRfc2ltcGxlX3BhcnRpdGlvbmVkCldIRVJFIHRvd24gPSAnTE9ORE9OJzs\&run_query=true\&tab=results) الاستعلام على النسخة المُقسَّمة من الجدول، يفحص ClickHouse 671 كتلة من الصفوف (\~ 5.5 مليون صف) ويعالجها خلال 90 مللي ثانية:

```sql theme={null}
SELECT MAX(price) AS highest_price
FROM uk.uk_price_paid_simple_partitioned
WHERE town = 'LONDON';
```

```response theme={null}
┌─highest_price─┐
│     594300000 │ -- 594.30 million
└───────────────┘

1 row in set. Elapsed: 0.090 sec. Processed 5.48 million rows, 27.95 MB (60.66 million rows/s., 309.51 MB/s.)
Peak memory usage: 163.44 MiB.
```

أما عند [تنفيذ](https://sql.clickhouse.com/?query=U0VMRUNUIE1BWChwcmljZSkgQVMgaGlnaGVzdF9wcmljZQpGUk9NIHVrLnVrX3ByaWNlX3BhaWRfc2ltcGxlCldIRVJFIHRvd24gPSAnTE9ORE9OJzs\&run_query=true\&tab=results) الاستعلام على الجدول غير المُقسَّم، فإن ClickHouse يفحص 241 كتلة (\~ مليوني صف) ويعالجها خلال 12 ميلي ثانية:

```sql theme={null}
SELECT MAX(price) AS highest_price
FROM uk.uk_price_paid_simple
WHERE town = 'LONDON';
```

```response theme={null}
┌─highest_price─┐
│     594300000 │ -- 594.30 million
└───────────────┘

1 row in set. Elapsed: 0.012 sec. Processed 1.97 million rows, 9.87 MB (162.23 million rows/s., 811.17 MB/s.)
Peak memory usage: 62.02 MiB.
```
