GH GambleHub

Sorğuların indeksləşdirilməsi və optimallaşdırılması

1) Indeksləşdirmə və optimallaşdırma məqsədləri

Gecikmə: P50/P95/P99 azaldılması.
Bant genişliyi: üfüqi miqyaslı olmadan QPS artımı.
Proqnozlaşdırıla bilər: sabit planlar və cavab vaxtında «sıçrayışların» olmaması.
Qənaət: daha az IO/CPU, bulud üçün daha az hesab.
Etibarlılıq: Düzgün giriş yolu ilə kilidlərin və deflokların azaldılması.

İnvariantlar:
  • Hər hansı bir optimallaşdırma düzgün və uyğun olmalıdır.
  • Metrik və plan loqlarında təsiri izləmək.

2) Indekslərin əsas strukturları və onları nə zaman tətbiq etmək

2. 1 B-Tree (defolt)

Bərabər/diapazonlar, çeşidləmə, 'ORDER BY'.
Ən vaxt/ID/status filtrləri üçün yaxşıdır.

2. 2 Hash

Təmiz bərabərliklər ('='), yaddaşda daha ucuz, lakin sifarişsiz (PG: məhdudiyyətlər aradan qaldırılır, lakin hələ də niş seçimdir).

2. 3 GIN / GiST (PostgreSQL)

GIN: massivlər/JSONB açarları, tam mətn (tsvector), containment ('@>').
GiST: geo, diapazonlar, kNN.

2. 4 BRIN (PostgreSQL)

«Təbii sıralanmış» masalar üzrə super ucuz indeks (append-only). Böyük cədvəllər ilə time-series üçün yaxşıdır.

2. 5 Bitmap (MySQL/InnoDB: yerli deyil; DW-SUBD/OLAP)

Aşağı kardinallıq və fasetlər üçün effektiv, daha çox sütun anbarlarında.

2. 6 Sütun indeksləri (ClickHouse)

Primary key + data skipping (minmax), secondary через `skip indexes` (bloom, set).
aqreqasiya və diapazonlar ilə OLAP sorğular.

2. 7 Çevirilmiş indekslər (Elasticsearch/OpenSearch)

Tam mətn, fasetlər, hibrid axtarış. Dəqiq filtrələr üçün keyword sahələri və doc values istifadə edin.

2. 8 MongoDB

Single, compound, multikey (massivlər), partial, TTL, text, hashed (vahid açar üçün).

3) Açarların və kompozit indekslərin layihələndirilməsi

3. 1 «Sol prefiks» qaydası

İndeks sahələrinin sırası istifadəni təyin edir.
'WHERE tenant_id =? AND created_at >=? ORDER BY created_at DESC` → индекс `(tenant_id, created_at DESC, id DESC)`.

3. 2 Tie-breaker

Sabit çeşidləmə və seek-paginasiya üçün unikal quyruq (adətən 'id') əlavə edin.

3. 3 Qismən/süzülmüş indekslər

Yalnız «isti» alt çoxluqları indeksləşdirin:
sql
CREATE INDEX idx_orders_paid_recent
ON orders (created_at DESC, id DESC)
WHERE status = 'paid' AND created_at > now() - interval '90 days';

3. 4 Örtük indeksləri

«Oxunan» sahələri indeksə daxil edin (MySQL: 'INCLUDE'; PG 11+: `INCLUDE`):
sql
CREATE INDEX idx_user_lastseen_inc ON users (tenant_id, last_seen DESC) INCLUDE (email, plan);

3. 5 Funksional/Hesablanabilir

Indeksdə açarları normallaşdırın:
sql
CREATE INDEX idx_norm_email ON users (lower(email));

4) Partiyalaşdırma və şardlaşdırma

4. 1 Partiyalaşdırma (PG native/cədvəl irsi; MySQL RANGE/LIST)

Vaxtına görə partiyaların rotasiyası ('daily/weekly') 'VACUUM/DELETE' -ni asanlaşdırır.
Indekslər yerli partiya → daha az B-Tree, daha sürətli plan.

sql
CREATE TABLE events (
tenant_id bigint,
ts timestamptz,
...
) PARTITION BY RANGE (ts);

4. 2 Partiyalaşdırma açarı

OLTP-də - 'tenant _ id' (yükün lokallaşdırılması).
time-series/OLAP-da - po 'ts' (diapazonlu sorğular).
Hibrid: '(tenant_id, ts)' + alt partiyalar.

4. 3 Şardlaşdırma

Consistent hashing/range-shard ilə 'tenant _ id' və ya vaxt.
Cross-shard sorğu → scatter-gather və k-way merge; cursor per-shard saxlamaq.

5) Statistika, kardinallıq və planlar

5. 1 Aktual statistika

Avtomatik analizi daxil edin ('autovacuum/autoanalyze'), «çirkli» paylamalar üçün 'default _ statistics _ target' artırın.

5. 2 Qabaqcıl Statistika (PG)

Korrelyasiya sütunları:
sql
CREATE STATISTICS stat_user_country_city (dependencies) ON country, city FROM users;
ANALYZE users;

5. 3 icra planı

'EXPLAIN (ANALYZE, BUFFERS, VERBOSE)' baxın; əsas sahələr:
  • `Rows`, `Loops`, `Actual time`, `Shared Read/Hit`, `Recheck Cond`.
  • Типы join: Nested Loop, Hash Join, Merge Join.
  • Seq Scan vs Index Scan/Only Scan/Bitmap Heap Scan.

5. 4 Planların sabitliyi

Parametrləşdirmə (prepared statements) pis planda «yapışa» bilər. Plan cache guardrails istifadə edin (PG: 'plan _ cache _ mode = force_custom_plan' problemli sorğular üçün) və ya sabitin «sürüşməsi».

6) Join və çeşidləmə optimallaşdırılması

6. 1 Strategiyalar

Nested Loop: kiçik xarici, daxili sürətli indeks.
Hash Join: böyük dəstlər, hash masa altında kifayət qədər yaddaş.
Merge Join: artıq mövcud qaydada sərfəli olan sıralanmış girişlər.

6. 2 join altında indekslər

Üçün 'A JOIN B ON B.a_id = A.id' → indeks 'B (a_id)'.
join sonra filter üçün - daxili masa filter sütunlarında indeks.

6. 3 çeşidləmə

Müvafiq indeks olmadan 'ORDER BY' -dən çəkinin; böyük dəstlərində çeşidləmə yol yaddaş/disk.

7) Sorğuların yenidən yazılması (query rewrite)

«Qar dənələri» alt sorğulardan qurtulun; JOIN-də açın.
CTE-inline (PG ≥ 12 inlines CTE default istifadə edin, lakin 'MATERIALIZED' lazım olduqda ara nəticəni düzəldə bilər).
'SELECT' → sahələri sıralayın (IO/şəbəkəyə qənaət).
Hesablamaları 'WHERE' -dən indeksləşdirilən formaya (əvvəlcədən təyin olunan sütunlar) köçürün.
Aqreqasiyalar: əvvəlcədən məcmu cədvəllər/incremental yeniləmə ilə materiallaşdırılmış performans.

8) Batching, limit və paginasiya

Batch-insert/update: paket 500-5000 əvəzinə vahid.
Seek-pagination '(sort_key, id)' əvəzinə dərin 'OFFSET'.
Çeşidlənmədən/joydan əvvəl dəstin limitlənməsi (push-down 'LIMIT').

9) Caching və Denormalization

Query-cache proqram səviyyəsi (açar = SQL + bind-vars + versiyası hüquqları).
Ağır aqreqatlar üçün Materialized views; rotasiya/refres planı.
Denormalizasiya: tez-tez oxunan hesablanan sahələri (endirim ilə qiymət) saxlayın, lakin sabitlik üçün trigger/fon vəzifəsi ilə.
Redis L2 kimi «isti» açarlar üçün (TTL və hadisə əlilliyi ilə).

10) Məşhur mühərriklərin xüsusiyyətləri

10. 1 PostgreSQL

Индексы: B-Tree, Hash, GIN/GiST, BRIN, partial, functional, INCLUDE.

Nümunə:
sql
CREATE INDEX idx_orders_tenant_created_desc
ON orders (tenant_id, created_at DESC, id DESC)
INCLUDE (amount, status);
Tam mətn:
sql
CREATE INDEX idx_docs_fts ON docs USING GIN (to_tsvector('russian', title          ' '          body));

10. 2 MySQL/InnoDB

Kompozit, örtücü indekslər (açar sahələrinə daxil olmaqla), testlər üçün görünməz indekslər:
sql
ALTER TABLE orders ALTER INDEX idx_old INVISIBLE; -- check risk-free plans

Histoqramlar üzrə statistika ('ANALYZE TABLE... UPDATE HISTOGRAM` в 8. 0).

10. 3 ClickHouse

Əsas açar = sıralama; 'ORDER BY (tenant_id, ts, id)'.

Keçid indeksləri:
sql
CREATE TABLE events (
tenant_id UInt64,
ts DateTime64,
id UInt64,
payload String,
INDEX idx_bloom_payload payload TYPE bloom_filter GRANULARITY 4
) ENGINE = MergeTree()
ORDER BY (tenant_id, ts, id);

10. 4 MongoDB

Kompozit/cizgi filmləri: sifariş vacibdir, filtr və çeşidləmə indeks ilə üst-üstə düşməlidir:
js db. orders. createIndex({ tenant_id: 1, created_at: -1, _id: -1 });
db. orders. createIndex({ status: 1 }, { partialFilterExpression: { archived: { $ne: true } } });

Diaqnoz üçün 'hint ()' istifadə edin, 'covered query'.

10. 5 Elasticsearch/OpenSearch

Keyword vs text sahələri; doc_values/aqreqatların çeşidlənməsi.
Heap seqmentasiyası: aqreqasiya - ağır; 'size' ilə məhdudlaşın və 'composite' aqreqasiyasını (səhifə seçimi) istifadə edin.
Dəqiq müqayisə tələb olunan yerlərdə analizatorları işə salmayın.

11) Rəqabət, kilid və MVCC

Qısa əməliyyatlar; ehtiyac olmadan 'REPEATABLE READ' altında «uzun» oxumaqdan çəkinin.
İndeks əməliyyatları da kilidləri alır (write throughput azaldılması).
Onlayn indeksləşdirməni planlaşdırın: 'CREATE INDEX CONCURRENTLY' (PG), 'ALGORITHM = INPLACE '/' ONLINE' (MySQL).
Saat/ID → indeksin «qaynar səhifələri» quyruğuna əlavə edin; açarı paylayın (UUIDv7/duz).

12) Müşahidə və SLO

Metriklər:
  • 'db _ query _ latency _ ms' (P50/P95/P99) sorğunun adı ilə.
  • `rows_examined`, `rows_returned`, `buffer_hit_ratio`.
  • `deadlocks`, `lock_wait_ms`, `temp_sort_disk_usage`.
  • 'Index Scan' gözlənilən yerdə 'Seq Scan' ilə planların payı.
  • DBB versiyasını/parametrlərini dəyişdirərkən reqress alertləri.
Log/Trace:
  • Eşik ilə slow query log daxil edin (məsələn, 200 ms).
  • Span sorğularının korrelyasiyası (trace_id).
  • Problemli sorğu planlarını çıxarın və retrospektiv üçün obyektin anbarında saxlayın.
SLO nümunəsi:
  • Oxunma P95 '<= 150 ms' zaman 'LIMIT <= 50' və «isti» tenant.
  • Qeydlərin P95 '<= 200 ms' 1000 sətrə qədərdir.

13) Təhlükəsizlik və çox tenant

Giriş nəzarəti sahələri üzrə indekslər ('tenant _ id', 'owner _ id') məcburidir.
Siyasətçilər (RLS/ABAC) ön filtr olmalıdır; əks halda optimallaşdırıcı səhv planlaşdırır.
Həssas sahələri açıq formada indeksləşdirməyin; hash/tokenlər istifadə edin.

14) Anti-nümunələr

Seek-kursor alternativi olmadan dərin 'OFFSET'.
«Hamısı üçün bir indeks» - yaddaş həddindən artıq yüklənməsi və write-path.
Kritik yollarda 'SELECT'.
Funksional indeks olmadan 'WHERE' sütununun üstündəki funksiyalar.
Köhnə statistikaya görə qeyri-sabit planlar.
Sabit sifariş gözləyərkən 'ORDER BY' olmaması.
Indekslər üçün indekslər: ROI <0, çünki bahalı qeyd/dəstək.

15) Giriş çek siyahısı

1. QPS və vaxt Top-N sorğular → 3-5 namizəd seçin.
2. «EXPLAIN ANALYZE» planlarını çıxarın, kardinallığı yoxlayın vs faktiki.
3. Indeksləri dizayn edin: sahə sırası, INCLUDE/partial/functional.
4. Böyük cədvəllər üçün partiyalaşdırma tətbiq edin (müvəqqəti/tenant açarları).
5. Sorğuları yenidən yazın: 'SELECT' çıxarın, sadə CTE-ləri birləşdirin, yığımı məhdudlaşdırın.
6. batching və seek-pagination daxil edin.
7. Cache konfiqurasiya: L1/L2, hadisələr üçün əlillik.
8. Planların monitorinqini və slow-log, reqresslər üçün alertlər daxil edin.
9. Real məlumat paylanması ilə yükləmə testləri aparın.
10. İnkişaf üçün bələdçiləri yeniləyin (ORM-xintlər, indeksləşdirmə, limitlər).

16) Nümunələr «əvvəl/sonra»

Qədər:
sql
SELECT FROM orders
WHERE status = 'paid'
ORDER BY created_at DESC
LIMIT 50 OFFSET 5000;
Sonra:
sql
-- Индекс: (status, created_at DESC, id DESC) INCLUDE (amount, currency)
SELECT id, amount, currency, created_at
FROM orders
WHERE status = 'paid'
AND (created_at, id) < (:last_ts,:last_id)   -- seek
ORDER BY created_at DESC, id DESC
LIMIT 50;

17) ORM və API protokolları

N + 1-dən çəkinin: acgöz nümunələr ('includes', 'JOIN FETCH', 'preload').
Sahələrin aydın proyeksiyaları, paginate kursor.
gRPC/REST: 'page _ size' limitini, 'sort' yazın, qeyri-şəffaf tokenlərdən istifadə edin.
Cache planı: parametrləşdirmə istifadə edin; Hər çağırışda «unikal» SQL yaratmayın.

18) Miqrasiya və istismar

Online indeksləri əlavə edin və INVISIBLE/CONCURRENTLY kimi qeyd edin, planları test edin, sonra dəyişdirin.
Indekslərin təftişləri - müntəzəm sanitar təmizləmə: köhnə sahələr üçün dublikatlar, istifadə olunmayan, «ölü».
Partiyanın rotasiya planı (köhnə) və 'VACUUM/OPTIMIZE' cədvəli.

19) Xülasə

Sorğuların optimallaşdırılması sistem mühəndisliyidir: düzgün açarlar və indekslər, dəqiq planlar, düşünülmüş partizanlaşdırma və şardlaşdırma, sorğularda nizam-intizam və ORM, keşləmə və müşahidə. Təsvir edilmiş nümunələrə riayət edərək, sürətli, proqnozlaşdırıla bilən və səmərəli, data artımına və yükə davamlı bir sistem əldə edəcəksiniz.

Contact

Bizimlə əlaqə

Hər hansı sualınız və ya dəstək ehtiyacınız varsa — bizimlə əlaqə saxlayın.Həmişə köməyə hazırıq!

İnteqrasiyaya başla

Email — məcburidir. Telegram və ya WhatsApp — istəyə bağlıdır.

Adınız istəyə bağlı
Email istəyə bağlı
Mövzu istəyə bağlı
Mesaj istəyə bağlı
Telegram istəyə bağlı
@
Əgər Telegram daxil etsəniz — Email ilə yanaşı orada da cavab verəcəyik.
WhatsApp istəyə bağlı
Format: ölkə kodu + nömrə (məsələn, +994XXXXXXXXX).

Düyməyə basmaqla məlumatların işlənməsinə razılıq vermiş olursunuz.