84 / 100

PARTIAL INDEX

Qismiy indekslar

Ushbu qo'llanmada PostgreSQLda jadvalning butun qatorlarini emas, balki faqat ko'rsatilgan shartga mos keladigan qismini indekslash uchun qismiy indekslar (Partial Indexes) dan qanday foydalanishni o'rganasiz.

Qismiy indekslarga kirish

Odatda indeks yaratilganda, PostgreSQL jadvaldagi har bir qator uchun indeks yozuvini tuzadi.

Biroq, ko'pincha siz faqat ma'lum bir qatorlar guruhi bo'yicha qidiruv qilasiz. Masalan:

  • Faqat faol foydalanuvchilar (WHERE is_active = true).
  • Faqat sotuvda mavjud bo'lgan tovarlar (WHERE discontinued = false).
  • Faqat to'lanmagan buyurtmalar (WHERE status = 'unpaid').

Bunday hollarda butun jadvalni indekslash disk xotirasini isrof qiladi va har bir INSERT/UPDATE paytida indeksni yangilash sekinlashadi.

PostgreSQL WHERE bandi bilan faqat kerakli qatorlar uchun indeks tuzish imkonini beradi. Bu qismiy indeks (Partial Index) deb ataladi.

Qismiy indeksning sintaksisi:

query.sql
CREATE INDEX [index_name]
ON table_name (column1, column2, ...)
WHERE condition;

Qismiy indekslarning afzalliklari

  1. Kichik hajm: Butun jadval o'rniga faqat kerakli qatorlar indekslangani sababli diskda juda kam joy egallaydi.
  2. Yuqori tezlik: Indeks daraxti ixcham bo'lgani uchun qidiruv juda tez bajariladi.
  3. Yozish amallari yengilligi: Boshqa (shartga to'g'ri kelmaydigan) qatorlar qo'shilganda yoki yangilanganda ushbu indeksga tegilmaydi.

Qismiy indeks amaliy misoli

Avval mahsulotlar jadvalini yaratamiz:

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,
  discontinued BOOL DEFAULT FALSE
);

Jadvalga 1000 ta mahsulot kiritamiz (ulardan 20% i sotuvdan chiqarilgan — discontinued = TRUE, 80% i esa faol sotuvda — discontinued = FALSE):

query.sql
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, discontinued)
      VALUES (
       'Product_' || i,
       ROUND((RANDOM() * 100 + 1)::numeric, 2),
       CASE WHEN RANDOM() < 0.2 THEN TRUE ELSE FALSE END
      );
   END LOOP;
END;
$$ 
LANGUAGE plpgsql;

SELECT insert_products(1000);

1) Qismiy indeks yaratish

Biz faqat sotuvda faol bo'lgan (discontinued = FALSE) mahsulotlarning narxiga qismiy indeks quramiz:

query.sql
CREATE INDEX idx_products_active_price 
ON products (price)
WHERE discontinued = FALSE;

2) Qismiy indeksdan foydalanish

Endi faol mahsulotlar orasidan arzonlarini qidiramiz:

query.sql
EXPLAIN SELECT
  name,
  price
FROM
  products
WHERE
  discontinued = FALSE
  AND price < 50;

Natija:

matn
                                         QUERY PLAN                                         
--------------------------------------------------------------------------------------------
 Bitmap Heap Scan on products  (cost=4.85..14.50 rows=150 width=21)
   Recheck Cond: ((price < '50'::numeric) AND (NOT discontinued))
   ->  Bitmap Index Scan on idx_products_active_price  (cost=0.00..4.81 rows=150 width=0)
         Index Cond: (price < '50'::numeric)

PostgreSQL so'rovdagi discontinued = FALSE sharti indeksning WHERE shartiga mos kelganini ko'rib, ixcham idx_products_active_price indeksidan foydalandi.

3) Shartga mos kelmaydigan so'rov

Agar endi sotuvdan chiqarilgan tovarlarni qidirsak:

query.sql
EXPLAIN SELECT
  name,
  price
FROM
  products
WHERE
  discontinued = TRUE
  AND price < 50;

Natija:

matn
                         QUERY PLAN                         
------------------------------------------------------------
 Seq Scan on products  (cost=0.00..18.50 rows=40 width=21)
   Filter: (discontinued AND (price < '50'::numeric))

Indeksda faqat discontinued = FALSE qatorlari mavjud bo'lgani sababli, ushbu so'rov uchun PostgreSQL odatiy Seq Scan (jadvalni to'liq o'qish) ni amalga oshiradi.

Qachon qismiy indekslardan foydalanish lozim?

  • Katta jadvallarda so'rovlarning aksariyati doimiy bitta shart bilan filtrlanganda (masalan, status = 'active').
  • Kam sonli qatorlar alohida ahamiyatga ega bo'lganda (masalan, millionta buyurtma orasida faqat 500 ta kutilayotgan buyurtmalar).
  • Noyoblikni faqat ma'lum qatorlar uchun ta'minlash lozim bo'lganda: CREATE UNIQUE INDEX ON users (email) WHERE is_deleted = FALSE; (o'chirilgan foydalanuvchilar bir xil emailga ega bo'lishi mumkin, ammo faollari emas).

Xulosa

  • Qismiy indeks (Partial Index) WHERE bandi orqali faqat ma'lum qatorlarni indekslaydi.
  • Disk xotirasini sezilarli darajada tejaydi va indeks orqali qidiruvni yanada tezlashtiradi.
  • Katta jadvallardagi statusli yoki bayroqli (boolean) ustunlar uchun juda mos keladi.