CodeGym /Kurslar /SQL SELF /İndekslərlə işləyərkən tipik problemlər

İndekslərlə işləyərkən tipik problemlər

SQL SELF
Səviyyə , Dərs
Mövcuddur

Ən müasir maşın belə, içinə benzin əvəzinə limonad töksən, işləməyəcək. PostgreSQL-də indekslərlə də eyni vəziyyətdir. Onlar çox güclü bir alətdir, amma ağılla istifadə etmək lazımdır. Gəlin, indekslərlə bağlı bir neçə tipik problemə baxaq.

Problem 1: artıq indeksləmə

Əvvəlcə əvvəlki-əvvəlki dərsin mövzusunu təkrarlayaq. Əgər bir cədvəldə çoxlu indeks varsa, PostgreSQL onların hər birini aktual saxlamaq üçün işləməyə məcbur olur. Bu, birbaşa yazma, yeniləmə və silmə əməliyyatlarına təsir edir. Axı hər bir indeksi təkcə yeniləmək yox, həm də sinxronizasiya etmək lazımdır!

Tutaq ki, bizdə students cədvəli var:

CREATE TABLE students (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100),
    email VARCHAR(255) UNIQUE,
    age INTEGER,
    grade INTEGER
);

Və sən "birdən lazım olar" deyə hər sütuna indeks yaratmağa qərar verdin:

CREATE INDEX idx_students_name ON students(name);
CREATE INDEX idx_students_age ON students(age);
CREATE INDEX idx_students_grade ON students(grade);

İndi təsəvvür et ki, 10 min yeni qeyd əlavə edirsən. PostgreSQL təkcə məlumatı cədvələ yazmır, həm də hər üç indeksi yeniləyir. Məlumat çoxdursa, yazma sürəti düşür və sistemin performansı zəifləyir.

Bu problemi necə həll etmək olar? İndeks yaratmazdan əvvəl özünə iki sual ver:

  1. Bu sütun filtrasiyada (WHERE), sıralamada (ORDER BY) və ya qruplaşdırmada (GROUP BY) nə qədər tez-tez istifadə olunur?
  2. Sorğu bu indeksi istifadə edəcək, yoxsa yenə də cədvəlin tam skanını edəcək?

Əgər hər iki suala cavabın "nadir hallarda" və ya "heç vaxt"dırsa, bu indeks sənə lazım deyil.

Problem 2: indeks üçün səhv sütun seçimi

Az müxtəlif dəyərləri olan sütunda indeks yaratmaq — üstü bağlı fincana çay tökməyə bənzəyir: nəticə demək olar ki, faydasız olacaq. Əgər sütunda cəmi 2-3 unikal dəyər varsa, PostgreSQL çox güman ki, indeksi istifadə etməyəcək, əvəzinə cədvəlin tam skanını edəcək.

Tutaq ki, bizdə courses cədvəli var:

CREATE TABLE courses (
    id SERIAL PRIMARY KEY,
    name VARCHAR(255),
    level VARCHAR(10) -- Yalnız 'Beginner', 'Intermediate' və ya 'Advanced' ola bilər
);

Və sən level sütununda indeks yaratmağa qərar verdin:

CREATE INDEX idx_courses_level ON courses(level);

Amma bu sorğu:

SELECT * FROM courses WHERE level = 'Beginner';

indeksi istifadə etməyə bilər, çünki PostgreSQL hesablayacaq ki, bütün cədvəli skan etmək indeksi yoxlamaqdan daha asandır. Bu, xüsusilə kiçik cədvəllər və az müxtəlif dəyərlər üçün aktualdır.

Ona görə indekslər yüksək kardinalitetli sütunlarda (yəni çoxlu unikal dəyəri olan) daha məntiqlidir. Az müxtəlif dəyərlər üçün başqa optimizasiya üsullarından, məsələn, cədvəl partitioning-dən istifadə etmək daha yaxşıdır.

Problem 3: köhnəlmiş indekslər

Bəzən indekslər yaradılır, amma sonra artıq istifadə olunmur və silinmir. Bu, masaüstündəki fayllar kimidir: əvvəlcə az olur — iki, üç, beş. Sonra isə birdən görürsən ki, lazım olanı tapmaq üçün ikonadan ikonaya baxıb vaxt itirirsən... Tanış hissdir, düzdür?

Tutaq ki, köhnə funksiya üçün indeks yaratdıq, sonra sorğuların məntiqini dəyişdik və yeni indeks əlavə etdik. Köhnə indeks artıq heç kimə lazım deyil, amma hələ də mövcuddur, yer tutur və yazma əməliyyatlarını ləngidir.

Bunun qarşısını almaq üçün indeksləri mütəmadi yoxlayıb analiz et. PostgreSQL-də bunun üçün rahat bir metrika var:

SELECT
    relname AS table_name,
    indexrelname AS index_name,
    idx_scan AS total_scans
FROM
    pg_stat_user_indexes
WHERE
    idx_scan = 0;

Burada idx_scan göstərir ki, hansı indeks neçə dəfə istifadə olunub. Əgər dəyər 0-dırsa, deməli indeks istifadə olunmur və onu silmək olar:

DROP INDEX idx_courses_level;

Problem 4: tez-tez yenilənən sütunlarda indekslər

Əgər tez-tez yenilənən sütunda indeks varsa, PostgreSQL hər dəyişiklikdə bu indeksi yenidən qurmalı olur. Bu isə performansı ciddi şəkildə azalda bilər.

Sifarişlər haqqında məlumat olan bir cədvəli təsəvvür et:

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    status VARCHAR(20), -- Bir neçə dəfə dəyişə bilər (məsələn, "yeni", "prosesdə", "tamamlanıb")
    total NUMERIC(10, 2)
);

Statuslara görə filtrasiya üçün status sütununda indeks yaradırsan:

CREATE INDEX idx_orders_status ON orders(status);

Amma əgər status hər qeyd üçün onlarla dəfə dəyişirsə, indeks performansı korlayır.

Belə vəziyyətdən qaçmaq üçün tez-tez dəyişən sütunlarda indeks yaratma. Əgər indeks mütləq lazımdırsa, partial index istifadə etməyi düşün:

CREATE INDEX idx_orders_status_partial
ON orders(status) 
WHERE status = 'prosesdə';

Beləliklə, indeks yalnız göstərilən dəyəri olan qeydlər üçün yenilənəcək.

Problem 5: Lazımsız sütunlarda UNIQUE məhdudiyyətləri

Unikal indekslər (UNIQUE) avtomatik olaraq məlumatların unikalığını qorumaq üçün yaradılır. Amma əgər unikalıq mütləq vacib deyilsə, bu indekslər artıq yük yaradır.

Tutaq ki, loglar üçün bir cədvəl yaratdıq:

CREATE TABLE logs (
    id SERIAL PRIMARY KEY,
    message TEXT,
    created_at TIMESTAMP UNIQUE
);

Əgər hər saniyə cədvələ minlərlə qeyd əlavə olunursa, created_at üzrə unikalığı qorumaq böyük yük yaradır.

Hər şey yaxşı olsun deyə, UNIQUE məhdudiyyətlərini yalnız həqiqətən lazım olan yerlərdə saxla. Bizim nümunədə, əgər created_at üzrə unikalıq vacib deyilsə, onu adi indekslə əvəz et:

CREATE INDEX idx_logs_created_at ON logs(created_at);

Problem 6: Kombinə edilmiş indekslərin səhv istifadəsi

Kombinə edilmiş indekslər (multi-column indexes) faydalıdır, əgər sorğular bir neçə sütuna görə filtrasiya və ya sıralama aparırsa. Amma belə indeksləri düzgün yaratmaq lazımdır, yoxsa istifadə olunmayacaq.

Tutaq ki, belə bir indeksimiz var:

CREATE INDEX idx_students_name_grade ON students(name, grade);

Bu indeks istifadə olunur, əgər sorğu hər iki sütuna görə filtrasiya və ya sıralama aparırsa:

SELECT * FROM students WHERE name = 'Alice' AND grade = 90;

Amma bu sorğu:

SELECT * FROM students WHERE grade = 90;

bu indeksi istifadə etmir, çünki name birinci gəlir.

Problemdən qaçmaq üçün kombinə edilmiş indeksləri yalnız sorğularda ən çox istifadə olunan ardıcıllıqla yarat. Əgər yalnız bir sütuna görə filtrasiya lazımdırsa, ayrıca indeks yarat.

Faydalı məsləhətlər

İndekslərin istifadəsini monitor et. PostgreSQL-də pg_stat_user_indexes adlı sistem görünüşü var, orada hansı indekslərin istifadə olunduğunu, hansının isə olmadığını görə bilərsən.

Sorğuları indekslərlə birlikdə optimizasiya et. Pis sorğular indekslərlə də pis qalacaq.

Silinməni unutma. Köhnəlmiş indekslər sadəcə yer tutur və yazma əməliyyatlarını ləngidir.

Vəssalam, dostlar! İndekslər — güclü bir alətdir, amma həmişə yadında saxla ki, böyük güclə böyük məsuliyyət gəlir. İndeksləri ağılla istifadə et, və sənin database-in SpaceX raketi kimi işləyəcək!

1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Artıq indeksləmə problemləri
Artıq indeksləmə problemləri
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION