Logo GH

PostgreSQL: best practices və indeksasiya

(Bölmə: Texnologiya və Infrastruktur)

Qısa xülasə

PostgreSQL - pul, KYC və iGaming-də hüquqi əhəmiyyətli qeydlər üçün «həqiqət nüvəsidir». Bu ACID zəmanət, güclü SQL və genişləndirilebilirlik verir. Turnirlərin və PSP vebhuklarının zirvələrinə tab gətirmək üçün: səriştəli sxem, indekslər, partiyalaşdırma, avtovakuum, WAL sazlama və müşahidə. Aşağıda - praktiklər və şablonlar dizayneri.

1) Memarlıq və SLO

PostgreSQL rolu: record lideri + oxu replikaları; isti ekranlar üçün - cache/proyeksiya (Redis/materiallaşdırılmış performans).
SLO nümunələri: p99 'INSERT/UPDATE' cüzdan ≤ 25-40ms; p99 balans oxu ≤ 10-15ms; lag replikaları ≤ 2-5 s; mövcudluğu ≥ 99. 9%.
read-after-write siyasəti: əməliyyatdan sonra istifadəçi ekranları liderdən oxunur və ya replikasiya gecikməsini gözləyir.

2) Sxemlərin dizaynı

Pul nüvəsinin normallaşdırılması (cüzdan, ledger) + oxumaq üçün denormallaşma (CQRS/proyeksiyalar).
Ciddi məhdudiyyətlər: 'NOT NULL', 'CHECK', 'UNIQUE', FK məqsədyönlü 'ON DELETE/UPDATE' (RESTRICT/SET NULL/NO ACTION).
Sxem versiyası: up/down miqrasiya, feature bayraqlar; isti vaxtlarda adını dəyişdirməkdən çəkinin.
Identifikatorlar: 'BIGINT' + ardıcıllığı (və ya paylanması üçün ULID/UUIDv7). İsti əlavələr üçün - ayrı bir tablespace/WAL cildindəki ardıcıllıqlar.

3) Indeksasiya: nə, harada və necə

3. 1 B-Tree (defolt)

Nə zaman: dəqiq uyğunluq, diapazonlar, sıralama, 'JOIN' FK.
Nümunələr: 'WHERE player_id =?', 'ORDER BY created_at DESC LIMIT 100'.

Təcrübələr:
  • Çox sütunlu indekslər - şərtlər qaydasına uyğun olun.
  • Covering: `INCLUDE (...)` для index-only scan.
  • Ayrı-ayrı indeks altında 'ORDER BY... DESC 'lent'.
sql
CREATE INDEX idx_tx_player_created_desc
ON tx (player_id, created_at DESC) INCLUDE (amount_cents, status);

3. 2 GIN (JSONB, massivlər, tam mətn)

Nə zaman: JSONB-axtarış açarları/yolları, tag massivləri, FTS.
Variantlar: triqramlar üçün 'gin _ trgm _ ops', 'jsonb _ path _ ops '/' jsonb _ ops'.
Təcrübə: axtarış sahələrini ciddi şəkildə məhdudlaşdırın və kardinallıq haqqında düşünün.

sql
CREATE INDEX idx_profile_jsonb_gin
ON player_profile USING GIN (data jsonb_path_ops);

-- Search by email/name with typos
CREATE EXTENSION IF NOT EXISTS pg_trgm;
CREATE INDEX idx_player_trgm ON player USING GIN (email gin_trgm_ops);

3. 3 GiST (geo/diapazonlar/imzalar)

Nə zaman: geolokasiya (IP-geo, radiuslar), intervallar, nearest-neighbor.
Pul nüvəsində daha az istifadə olunur, geo məhdudiyyətlər/məsuliyyətli oyun üçün faydalıdır.

3. 4 BRIN (böyük «apendiks» -tables vaxt)

Nə zaman: milyardlarla sətir, təbii vaxt korrelyasiyası (bahis/hadisə jurnalları).
Üstünlüklər: kiçik ölçülü, ucuz xidmət.
Mənfi cəhətləri: kobud seçicilik → partiyalaşdırma ilə birləşir.

sql
CREATE INDEX idx_bets_brin ON bets USING BRIN (created_at) WITH (pages_per_range = 64);

3. 5 Hash

Nadir hallarda lazımdır: diapazonlar olmadıqda bir sütun bərabərliyi; Daha çox B-Tree kifayətdir.

3. 6 Qismən və ifadələr

Partial index: isti alt çoxluqları sürətləndirir (aktiv, 'status =' pending ').
Expression index: açar ('lower (email)', '(data->>' psp _ tx ')').

sql
CREATE INDEX idx_withdraw_pending ON withdrawals (player_id)
WHERE status = 'pending';

CREATE INDEX idx_tx_psp_tx ON tx ((data->>'psp_tx'));

3. 7 Antipattern indeksləri

«Hər şey üçün indeks»: həddindən artıq indekslər yazmağa və VACUUM-a mane olur.
Təkrarlanan indekslər (eyni sütun/sıra).
Çox aşağı kardinallığı olan sütun üçün indeks (məsələn, 2 qiymətli 'status') - qismən edin.

4) Partiyalaşdırma

Niyə: bloat azaltmaq, VACUUM/scan sürətləndirmək, retention/arxiv asanlaşdırmaq.
Sxemlər: RANGE tarixinə görə (gün/həftə); Böyük istifadəçi cədvəlləri üçün 'player _ id' HASH; birləşmiş.
Rotasiya təcrübəsi: əvvəlcədən gələcək partiyalar yaratmaq, 'ATTACH PARTITION', köhnə arxiv - 'DETACH' + hərəkət.

sql
CREATE TABLE bets (
bet_id BIGINT PRIMARY KEY,
player_id BIGINT NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
amount_cents BIGINT NOT NULL
) PARTITION BY RANGE (created_at);

CREATE TABLE bets_2025_11_05 PARTITION OF bets
FOR VALUES FROM ('2025-11-05') TO ('2025-11-06');

5) Minimum parçalanma ilə əlavələr/yeniləmələr

HOT-Updates: Səhifədə boş yer üçün isti cədvəllərdə 'fillfactor' (məsələn, 90) saxlayın.
TOAST: böyük JSONB/mətnlər - kompakt nəzarət; böyük sahələri ayrı bir cədvəldə saxlayın.
UPSERT: 'ON CONFLICT istifadə... DO UPDATE 'idempotent məntiqi ilə.

sql
INSERT INTO wallet (player_id, balance_cents, updated_at)
VALUES ($1, $2, now())
ON CONFLICT (player_id) DO UPDATE
SET balance_cents = wallet. balance_cents + EXCLUDED. balance_cents,
updated_at = now();

6) Əməliyyatlar, bloklama və rəqabət

İzolyasiya səviyyələri: əksər yollar üçün 'READ COMMITTED'; 'REPEATABLE READ '/' SERIALIZABLE' nöqtəli (hesabatlar, offline batches). Onları uzun müddət saxlamayın.
Bloklama növləri: row-level (pessimizm 'FOR UPDATE'), table-level (DDL), paylanmış myutekslər üçün advisory locks.
Deadlocks: qısa əməliyyatlar, varlıqların yenilənməsi üçün vahid prosedur, taymaut ('lock _ timeout', 'statement _ timeout').
Tapşırıq növbələri: paylanmış work hovuzu üçün 'SKIP LOCKED'.

sql
-- batch processor removes work without racing
SELECT id FROM jobs
WHERE status='pending'
FOR UPDATE SKIP LOCKED
LIMIT 100;

7) Avtovağlama, statistika və bloat

VACUUM/ANALYZE: Cari statistikanı ('default _ statistics _ target') saxlayın, isti cədvəllərdə AV-nı sürükləyin (aşağıda işlənmə həddi).
wraparound (age (txid) <2 milyard), 'vacuum _ freeze _ min _ age'.
bloat-control: ağır indekslərdə müntəzəm reindex/CLUSTER; partizanlaşdırma problemin miqyasını azaldır.

Siyasət nümunəsi (cədvəl parametrləri):
sql
ALTER TABLE tx SET (
autovacuum_vacuum_scale_factor = 0. 05,
autovacuum_analyze_scale_factor = 0. 02,
autovacuum_vacuum_cost_limit = 4000
);

8) Yaddaş, yoxlama nöqtələri və WAL

Yaddaş

'shared _ buffers': 20-25% RAM (profildən asılıdır).
'work _ mem': əməliyyat üçün! Mühafizəkar şəkildə (məsələn, 8-64MB) qurun və hesabat rolları üçün nöqtəli şəkildə artırın.
'maintenance _ work _ mem': böyük indekslər/bərpa (tapşırıq 512MB-2GB).

WAL və çek nöqtələri

WAL üçün NVMe, ayrı bir cild; 'wal _ compression = on'.
'checkpoint _ timeout' 10-15 min, 'max _ wal _ size' dəyişiklik həcmi altında, 'checkpoint _ completion _ target ≈ 0. 9`.
Əlavələrin zirvələri üçün - batch əlavələri və qrup kommitləri.

9) Replikasiya və uğursuzluğa davamlılıq

Lider replikalar: RPO ≈ 0-30s üçün ən yaxın (yarı-sync) üçün sinxron; oxu/analitika üçün asenxron.
Promosyon və fencing: Patroni/replika-menecer; «ikili lider» istisna.
Hot standby: 'hot _ standby _ feedback' diqqətlə (böyümə bloat), daha yaxşı - replikalarda uzun əməliyyatları təmin edin.

10) Backup və PITR

Tam + artım arxası, ofsayt surətləri; WAL üçün 'archive _ command'.
PITR: stendlərdə vaxt nöqtəsinə qədər bərpa edin; RPO/RTO (cüzdan - dəqiqə, log - on dəqiqə) tənzimləmək.
DR təlimləri (game day): müntəzəm bərpa yoxlaması.

11) JSONB və «çevik sxem» modeli

JSONB nadir oxunan/dəyişən atributlar (KYC metadata, PSP parametrləri) üçün əladır.
Relyasiya sütunlarında məcburi sahələri ciddi şəkildə təsdiqləyin; JSONB - nüansların «quyruğu» üçün.
Indeksasiya: istifadə olunan yollar üzrə GIN nöqtəsi; «hər şeyə bir nəhəng GIN» çəkinin.

sql
-- partial GIN index only for documents with the desired key
CREATE INDEX idx_kyc_docnum ON kyc USING GIN ((data->'doc'->'number'))
WHERE data? 'doc';

12) Tam mətn və fuzzy-axtarış

Daxili FTS: 'tsvector' + GIN; 'pg _ trgm'.
Ağır axtarış/oyun üçün - axtarış sisteminə (ES/OpenSearch) çıxarılması və PG-də link/metadata saxlamaq.

13) Müşahidə və profil

pg_stat_statements: top yavaş/tez-tez sorğular, normallaşdırma.
EXPLAIN (ANALYZE, BUFFERS): planları oxuyun, isti yollarda seq scan axtarın.
Metriklər: TPS, p95/p99, kontrol nöqtələri, 'replication _ lag', deadlocks, bloat, AV dövrləri, cache-hit ≥ 95%.
Alertlər: laqların böyüməsi, «idle in transaction», gözlənilməz seq scan, WAL-fırtına.

14) Bağlantı hovuzu və hazırlanmış sorğular

Puller (PgBouncer) 'transaction' rejimində veb trafik üçün; 'session' - uzun kursorlar/arxa ofis üçün.
Prepared statements/parametrləşdirilməsi → daha az parsing, sabit planlar.
Maksimum bekend sayını məhdudlaşdırın ('max _ connections' aşağı; hovuz klapan götürür).

15) Təhlükəsizlik və uyğunluq

Tranzit TLS, disk şifrələmə, KMS/xarici açarlar.
RBAC: minimum hüquqlar, rolların bölünməsi oxu/yazma/admin.
Multi-tenant ssenarilər üçün RLS (Row-Level Security).
PII: maskalama/təxəllüs, saxlama müddəti.
Audit: 'pgaudit '/kritik cədvəllərdə audit tetikleyiciləri (cüzdan/ledger).

16) iGaming üçün standart şablonlar

16. 1 Cüzdan və ledger (ciddi uyğunluq)

Индексы: `wallet(player_id PK)`, `ledger(player_id, ts DESC)` + `INCLUDE (delta_cents, reason)`.
Əməliyyat balansı yeniləyir və ledger-də yazır; semi-sync replikasiyası; yalnız proyeksiya kimi cache.

16. 2 Bahis tarixi (yüksək TPS, oyunçu/vaxt oxu)

Gün/həftə partizanlaşdırma, BRIN vaxt + B-Tree '(player_id, created_at DESC)'.
'DETACH PARTITION' vasitəsilə Retenshn → OLAP arxivləşdirilməsi.

16. 3 PSP vebhukları (burstlar, retralar)

«Xam» hadisələrin növbəsi (append-only), vaxtına görə partiyalar, qismən indeks 'status =' pending '.
İdempotentlik 'idempotency _ key '/' psp _ tx' (UNIQUE).

17) Giriş çek siyahısı

1. SLO və read-after-write siyasətini düzəldin.
2. Real sorğular üçün əsas indeksləri dizayn edin (sorğu profili).
3. Retenshn/append nümunələri olan yerdə partizanlaşdırmanı daxil edin.
4. AV/ANALYZE-ni qaynar cədvəllərdə qurun, bloat/wraparound-u izləyin.
5. Pik pəncərələrin altında yaddaş, WAL və check-point.
6. Bağlantı hovuzunu və 'pg _ stat _ statements'; alertlər qurmaq.
7. Replikasiya + DR + PITR - məcburi; təlimlər keçirin.
8. JSONB və GIN-i yalnız lazımi yollarla məhdudlaşdırın; partial indexes istifadə edin.
9. Əməliyyatların müddətini minimuma endirin, work-növbələr üçün 'SKIP LOCKED' istifadə edin.
10. Audit/PII/şifrələmə/rol modeli - ödənişlər başlamazdan əvvəl.

18) Antipattern

Hər şey üçün bir «universal» indeks və sorğu analizi yoxdur.
Uzun «asılı» əməliyyatlar ('idle in transaction') → bloklama/böyümə bloat.
Laq nəzərə alınmadan read-after-write üçün replikalara güvənmək.
Hər şeyi JSONB-da saxlayın və bütün sənədi bir GIN ilə indeksləyin.
Sıfır VACUUM/ANALYZE nəzarəti və lag/kontrol nöqtələrinin monitorinqinin olmaması.
Kütləvi miqrasiyalar/DDL pik saatlarda.

19) Faydalı snippet

Sorğu və bufer planı

sql
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT amount_cents
FROM ledger
WHERE player_id = $1
ORDER BY ts DESC
LIMIT 100;

«Ağır» sorğuların profilləşdirilməsi

sql
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
SELECT query, calls, total_exec_time, mean_exec_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;

Partiyaların rotasiyası (ideya)

sql
-- create a party for tomorrow
CREATE TABLE bets_2025_11_06 PARTITION OF bets
FOR VALUES FROM ('2025-11-06') TO ('2025-11-07');

Nəticələr

PostgreSQL yükün xətti artımı ilə iGaming platformasında «pul və həqiqəti» çəkməyə qadirdir - indekslər, partiyalar, avtovağlama, WAL/yaddaş, replika/DR və müşahidə olunursa. Sorğu profili və SLO ilə başlayın, real nümunələr üçün indekslər qurun, isti cədvəlləri təcrid edin, ciddi əməliyyat gigiyenasını yandırın və baza turnirlər və pik ödənişləri saxlayacaq.

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!

Telegram
@Gamble_GC
İ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.