85 / 100

COVERING INDEX

Qamrovchi indekslar - INCLUDE

Ushbu qo'llanmada PostgreSQLda INCLUDE bandidan foydalanib qamrovchi indekslar (Covering Indexes) yaratish va jadvalning asosiy fayliga (heap) murojaat qilmasdan, to'g'ridan-to'g'ri faqat indeksning o'zidan ma'lumot o'qish (Index Only Scan) usulini o'rganasiz.

Qamrovchi indeks nima?

Odatda, indeks yordamida qidiruv amalga oshirilganda (Index Scan), PostgreSQL avval indeks daraxtidan kerakli qatorning manzilini topadi, so'ngra so'rovda so'ralgan boshqa ustunlar qiymatini olish uchun jadvalning asosiy ma'lumotlar blokiga (heap file) borib o'qiydi. Bu qo'shimcha disk operatsiyasini (I/O) talab qiladi.

Agar so'rov talab qilayotgan barcha ustunlar indeksning o'zida mavjud bo'lsa, PostgreSQL jadvalning o'ziga murojaat qilishga umuman hojat qolmaydi. U barcha ma'lumotlarni bevosita indeksdan o'qib beradi. Bu Index Only Scan deb ataladi va so'rovni maksimal darajada tezlashtiradi.

Bunday indeks qamrovchi indeks (Covering Index) deb yuritiladi.

INCLUDE bandi

PostgreSQL 11 versiyasidan boshlab indeks yaratishda INCLUDE bandi taqdim etilgan:

query.sql
CREATE INDEX [index_name]
ON table_name (indexed_columns)
INCLUDE (extra_columns);

Farqi shundaki:

  • indexed_columns — qidiruv, filtrlash va saralash uchun ishlatiladi (B-Tree daraxtining asosiy kalitlari).
  • extra_columns (INCLUDE ichidagi ustunlar) — indeksning faqat eng pastki barg tugunlarida (leaf nodes) qo'shimcha yuk sifatida saqlanadi. Ular daraxt tuzilishini kattalashtirmaydi va B-Tree kalitlari hajmiga cheklov qo'ymaydi, ammo Index Only Scan amalga oshirish uchun yetarli bo'ladi.

Qamrovchi indeks amaliy misoli

Avval mahsulotlar jadvalini yaratib, sinov ma'lumotlarini kiritamiz:

query.sql
DROP TABLE IF EXISTS products CASCADE;

CREATE TABLE products (
  id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  price DEC(10, 2) NOT NULL
);

-- 1000 ta qator qo'shamiz
CREATE OR REPLACE FUNCTION insert_products (n INT) 
RETURNS VOID 
AS 
$$
DECLARE
   i INT;
BEGIN
   FOR i IN 1..n LOOP
      INSERT INTO products (name, price)
      VALUES (
       'Product_' || i, 
       ROUND((RANDOM() * 100 + 1)::numeric, 2)
      );
   END LOOP;
END;
$$ 
LANGUAGE plpgsql;

SELECT insert_products(1000);

1) INCLUDE bilan qamrovchi indeks yaratish

Aytaylik, ilovamizda mahsulot nomi bo'yicha qidirib, uning narxini olish juda ko'p takrorlanadi:

query.sql
SELECT name, price FROM products WHERE name = 'Product_100';

Biz name bo'yicha indeks yaratamiz va INCLUDE yordamida price ustunini unga biriktiramiz:

query.sql
CREATE INDEX idx_products_name_cover_price 
ON products(name)
INCLUDE (price);

2) So'rov rejasini tekshirish (Index Only Scan)

query.sql
EXPLAIN ANALYZE
SELECT name, price
FROM products 
WHERE name = 'Product_100';

Natija:

matn
                                                                     QUERY PLAN                                                                     
----------------------------------------------------------------------------------------------------------------------------------------------------
 Index Only Scan using idx_products_name_cover_price on products  (cost=0.28..4.29 rows=1 width=17) (actual time=0.035..0.036 rows=1 loops=1)
   Index Cond: (name = 'Product_100'::text)
   Heap Fetches: 0
 Planning Time: 0.120 ms
 Execution Time: 0.052 ms

E'tibor bering:

  • Index Only Scan — PostgreSQL jadvalga kirmasdan faqat indeksning o'zidan barcha ma'lumotlarni o'qidi!
  • Heap Fetches: 0 — asosiy jadval bloklariga (heap) nol marta murojaat qilindi.

Agar biz oddiy CREATE INDEX ON products(name) yaratganimizda, narxni olish uchun albatta heap faylga borib o'qishi kerak bo'lardi (Heap Fetches > 0).

Qachon INCLUDE ishlatish kerak?

  • Katta hajmdagi ustunlar (masalan, matn yoki katta sonlar) qidiruv mezonida qatnashmay, faqat natija sifatida (SELECT ro'yxatida) qaytarilishi kerak bo'lganda.
  • Noyob indekslarda (UNIQUE INDEX): siz faqat ma'lum ustunning noyobligini saqlagan holda qo'shimcha ustunlarni qamrab olmoqchi bo'lsangiz:
    query.sql
    CREATE UNIQUE INDEX ON users (email) INCLUDE (user_id, full_name);
    
    Bu yerda faqat email noyob bo'ladi, lekin uning qidiruvida user_id va full_name ham bevosita indeksdan olinadi.

Xulosa

  • Qamrovchi indeks (Covering Index) so'rovga kerakli barcha ma'lumotlarni o'zida saqlaydi va Index Only Scan imkoniyatini beradi.
  • INCLUDE bandi daraxt kalitiga ta'sir qilmasdan barg tugunlariga qo'shimcha ustunlarni biriktirish uchun qulay vositadir.
  • Heap Fetches: 0 eng tez va tejamkor o'qish operatsiyasini bildiradi.