İndekslər — şübhəsiz, database-lərini sürətləndirmək üçün əla üsuldur, amma necə deyərlər, “ən yaxşı yaxşıya düşməndir”. Hər indeks faydalı olmur, hətta çox indeks əlavə etsən, bu, köməkdən çox ziyan verə bilər. Qəribə səslənir, amma elədir. Gəlin, bir az araşdıraq.
Təsəvvür elə böyük bir kitabxana var, orda kitab axtarmaq üçün bir neçə kataloq var — məsələn, müəllifə görə, janra görə, çap ilinə görə. Hər belə kataloq lazımi kitabı tez tapmağa kömək edir. Amma kataloqlar həddindən artıq çox olsa — məsələn, hər ad sözünə və ya hər detal üçün ayrıca kataloq olsa — kömək əvəzinə qarışıqlıq yaranacaq: axtarış daha çox vaxt aparacaq, kataloqlar çox yer tutacaq və kitabxanaçı daim bu siyahıları yeniləməli olacaq.
Database-də indekslər də təxminən belə işləyir: onlar lazımi məlumatı tez tapmağa kömək edir, amma çox olanda, hər yeni qeyd əlavə və ya dəyişəndə onları yeniləmək çətinləşir. Diskdə də əlavə yer tutur. Üstəlik, indekslər çox olanda sistem hansı indeksdən istifadə edəcəyini seçməkdə çətinlik çəkə bilər.
Ona görə də, kitabxanadakı kataloqlar kimi, indekslərdə də həddi aşmamaq vacibdir — bir neçə faydalı və effektiv indeks, onlarla lazımsız indeksdən yaxşıdır.
Gəlin, "PostgreSQL detektivləri" oynayaq. Təsəvvür elə, bir sütun üçün üç indeks əlavə etmisən. Düşünmüsən ki, bu, performansı artıracaq. Amma təsəvvür elə:
- Əgər sənin cədvəlin böyük bir tələbə siyahısıdırsa və üç indeks varsa, hər yeni tələbə əlavə edəndə üç indeks də yenilənəcək. Bu, “sürətlənmə” kimi səslənmir, düzdür?
- Və əgər səndə 10 belə cədvəl varsa, hər biri indekslərlə doludursa? Database-in performansı dərinliyə gedəcək.
Artıq indeksləmə probleminin olub-olmadığını necə bilmək olar?
Birinci addım, problemin olub-olmadığını anlamaq üçün mövcud indekslərə baxmaqdır. PostgreSQL-də bunu belə edə bilərsən:
\d cədvəl_adı
Bu komanda sənə cədvəli, sütunları və bağlı indeksləri göstərəcək. Əgər bir cədvəllə bağlı çoxlu indeks görürsənsə, artıq düşünməyə dəyər.
Daha bir faydalı alət — sistem görünüşü pg_stat_user_indexes-dir. O, indekslərin nə qədər aktiv istifadə olunduğunu göstərir və “ölü yük” olan indeksləri tapmağa kömək edir:
SELECT
relname AS cədvəl_adı,
indexrelname AS indeks_adı,
idx_scan AS indeks_axtarışları
FROM
pg_stat_user_indexes
WHERE
idx_scan = 0;
Əgər idx_scan sıfırdırsa, deməli, indeks heç bir sorğuda istifadə olunmayıb. Belə indeks — silinməyə namizəddir.
Artıq indeksləməyə nümunə
Gəlin, istifadəçilərlə bağlı bir cədvəl təsəvvür edək:
CREATE TABLE users (
user_id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE,
username VARCHAR(50),
created_at TIMESTAMP DEFAULT NOW()
);
Və bizdə üç indeks var:
-- email üçün indeks
CREATE INDEX idx_users_email ON users (email);
-- username üçün indeks
CREATE INDEX idx_users_username ON users (username);
-- created_at üçün indeks
CREATE INDEX idx_users_created_at ON users (created_at);
İndi baxaq, hansı tipik sorğular edirik:
- İstifadəçini email ilə axtarmaq.
- İstifadəçini username ilə axtarmaq.
- İstifadəçiləri
created_at-a görə sıralamaq.
İndekslər faydalı görünür. Amma bir məsələ var: əgər bu sorğular nadir hallarda (məsələn, həftədə bir dəfə) işlədilirsə, indeks yaratmaq özünü doğrultmur. Üstəlik, bu indekslərin bəziləri heç vaxt istifadə olunmursa, onlar sadəcə insert və update əməliyyatlarını yavaşladır.
Məsələn: deyək ki, users cədvəlində belə məlumatlar var:
| user_id | username | created_at | |
|---|---|---|---|
| 1 | alex.lin@mail.com | alexlin | 2024-06-15 10:23:00 |
| 2 | anna.min@mail.com | annamin | 2024-06-16 12:47:00 |
| 3 | otto.song@mail.com | ottosong | 2024-06-17 08:30:00 |
| 4 | maria.chi@mail.com | mariachi | 2024-06-18 14:10:00 |
Əgər username ilə sorğular demək olar ki, heç vaxt olmursa, idx_users_username indeksi heç istifadə olunmur (idx_scan = 0) və optimizasiya üçün silinə bilər.
Yəni indeks — əla alətdir, amma onu ağılla istifadə etmək lazımdır. Bir neçə faydalı və tez-tez istifadə olunan indeks, çoxlu lazımsız indeksdən yaxşıdır.
Artıq indeksləmədən necə qaçmaq olar
- İstifadə olunan indekslərin analizi. Dediyimiz kimi,
pg_stat_user_indexesilə indekslərin istifadə statistikasına bax. Əgər indeks demək olar ki, istifadə olunmur, yəqin ki, onu silmək olar:
DROP INDEX IF EXISTS indeks_adı;
- İndeksləri yalnız tez-tez istifadə olunan sorğular üçün yarat. İndeks əlavə etməzdən əvvəl özünə sual ver:
- Bu sütun tez-tez
WHERE,ORDER BY,GROUP BY-da istifadə olunur? - Cədvəldə məlumat çoxdur?
- Sorğu indeks olmadan həqiqətən çox yavaş işləyir?
Əgər bu suallardan heç olmasa birinə “yox” cavabı verirsənsə, indeks yaratmaq artıq ola bilər.
- Birləşmiş indekslərdən istifadə et. Əgər tez-tez bir neçə sütunu bir sorğuda istifadə edirsənsə, hər sütun üçün ayrıca indeks yaratmaq əvəzinə birləşmiş indeks yarat:
CREATE INDEX idx_users_email_username ON users (email, username);
Bu, email və username ilə filtrasiya olunan sorğuları sürətləndirəcək.
- Mövcud indeksləri mütəmadi yoxla. Database böyüdükcə sorğuların da dəyişə bilər. Bir il əvvəl faydalı olan indeks bu gün artıq lazım olmaya bilər. Vaxtaşırı indekslərini yoxla və istifadə olunmayanları sil.
İndekslərin minimallaşdırılması nümunəsi
Gəlin, users cədvəlinə qayıdaq. Üç ayrı indeks əvəzinə belə optimizasiya edə bilərik:
created_atüçün ayrıca indeks silinsin, əgər bu sütun üzrə sıralama nadir hallarda olur.emailvəusernameüçün iki ayrı indeks əvəzinə birləşmiş indeks yarat:
CREATE INDEX idx_users_email_username ON users (email, username);
Nəticə: balansın sirri nədədir?
Proqramlaşdırmanın bir çox sahəsində olduğu kimi, burada da minimalizm prinsipi işləyir: “Nə qədər az, o qədər yaxşı”. Hər sütunu indeksləməyə ehtiyac yoxdur, sadəcə edə bildiyin üçün. Fikirləş, indeks sənə nə üçün lazımdır və sorğunun performansını nə qədər yaxşılaşdıracaq. Prakik ol və unutma: yaxşı developer hər yerə indeks əlavə edən deyil, onların təsirini başa düşən və effektiv istifadə edən adamdır.
İndi bu alət sənin əlindədir və artıq indeksləmə fəlakətinin qarşısını ala bilərsən, database-in gepard kimi sürətli, lazımsız indekslərlə yüklənmiş tısbağa kimi yavaş olmayacaq.
GO TO FULL VERSION