CodeGym /Kurslar /SQL SELF /Transaksiyaların icrası zamanı anomaliyalar: Dirty...

Transaksiyaların icrası zamanı anomaliyalar: Dirty Read, Non-Repeatable Read, Phantom Read

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

Gəlin bir də transaksiyaların növlərinə baxaq! Database transaksiyaları dünyasında üç əsas "pis oğlan" var ki, gününüzü korlaya bilər: Dirty Read, Non-Repeatable ReadPhantom Read. Bu "anomaliyalar" transaksiyaların kifayət qədər izolə olunmamasından yaranır. Bu gün baxacağıq ki, bu pis oğlanlar kimdir, necə işləyirlər və ən əsası — onlarla necə mübarizə aparmaq olar.

Misallara keçməzdən əvvəl, gəlin yadımıza salaq ki, bunlar nə deməkdir.

  • Dirty Read (Çirkli oxuma):
    Sən dəyişdirilmiş məlumatı oxuyursan, amma həmin məlumatı dəyişən transaksiyanın hələ COMMIT olunmayıb və ya, daha da pis, ROLLBACK oluna bilər. Bu elə bil ki, dostuna pul göndərirsən, balansına baxırsan və görürsən ki, kasıbsan, amma sonra fikrini dəyişib pulu özünə qaytarırsan. Sehr!

  • Non-Repeatable Read (Təkrarlanmayan oxuma):
    Bir transaksiyada eyni məlumatı iki dəfə oxuyursan, amma bu iki oxuma arasında başqa bir transaksiya həmin məlumatı dəyişir və sən iki fərqli nəticə görürsən. Bu elə bil ki, pasportunda doğum tarixinə baxırsan, sonra onu dostuna verirsən, o da rəqəmləri dəyişir, sən bir də baxırsan və doğum tarixini dəyişmiş görürsən.

  • Phantom Read (Fantom oxuma):
    Eyni sorğunu iki dəfə edirsən, amma ikinci dəfə başqa bir transaksiya əlavə sətir əlavə edib və sən artıq əlavə sətrləri görürsən. Bu elə bil ki, otaqdakı adamları sayırsan, kimsə gizlicə əlavə dostlar gətirir.

Dirty Read problemi

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

CREATE TABLE accounts (
    account_id SERIAL PRIMARY KEY,
    owner TEXT NOT NULL,
    balance NUMERIC(10, 2) NOT NULL
);
INSERT INTO accounts (owner, balance) VALUES ('Alice', 1000), ('Bob', 500);

Transaksiya 1 balansı dəyişir, amma hələ bitməyib, Transaksiya 2 isə eyni anda bu məlumatı oxumağa çalışır.

Transaksiya 1:

BEGIN;
UPDATE accounts SET balance = balance - 200 WHERE owner = 'Alice';
-- Alice-in balansı oldu 800, amma transaksiyanın sonu hələ gəlməyib.

Transaksiya 2:

BEGIN;
SELECT balance FROM accounts WHERE owner = 'Alice'; -- Balansı görürük: 800 (çirkli oxuma).
ROLLBACK; -- Transaksiya 1 geri qaytarılır.

İndi Transaksiya 2 səhv məlumatla işləyir, çünki Transaksiya 1 dəyişiklikləri ləğv etdi. Bunu READ COMMITTED isolation səviyyəsi ilə həll etmək olar, hansı ki, təsdiqlənməmiş transaksiyaların dəyişikliklərini görməyə imkan vermir.

Non-Repeatable Read problemi

Təsəvvür et ki, Transaksiya 1 məlumatı oxuyur, başqa bir transaksiya onu dəyişir və Transaksiya 1 yenidən oxuyur. Məlumat artıq fərqlidir.

Transaksiya 1:

BEGIN;
SELECT balance FROM accounts WHERE owner = 'Bob'; -- Balansı görürük: 500.

Transaksiya 2 paralel olaraq:

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE owner = 'Bob';
COMMIT;

Transaksiya 1 yenidən:

SELECT balance FROM accounts WHERE owner = 'Bob'; -- Balansı görürük: 400.
COMMIT;

Gördün, bir transaksiyanın içində məlumat dəyişdi. Real həyatda bu, məsələn, maliyyə hesabatlarında kritik ola bilər. Bunu daha yüksək isolation səviyyəsi ilə həll etmək olar, məsələn, REPEATABLE READ.

Phantom Read problemi

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

CREATE TABLE orders (
    order_id SERIAL PRIMARY KEY,
    customer TEXT NOT NULL,
    total NUMERIC(10, 2) NOT NULL
);
INSERT INTO orders (customer, total) VALUES ('Alice', 100), ('Bob', 200);

Transaksiya 1 sifarişlərin sayını sayır, başqa bir transaksiya yeni sifariş əlavə edir və Transaksiya 1 yenidən sayır.

Transaksiya 1:

BEGIN;
SELECT COUNT(*) FROM orders; -- Görürük: 2.

Transaksiya 2 paralel olaraq:

BEGIN;
INSERT INTO orders (customer, total) VALUES ('Charlie', 300);
COMMIT;

Transaksiya 1 yenidən:

SELECT COUNT(*) FROM orders; -- Görürük: 3. Yeni "fantom" sifariş gəldi!
COMMIT;

Fantom oxumanı aradan qaldırmaq üçün SERIALIZABLE isolation səviyyəsi lazımdır, hansı ki, nəticəyə təsir edən paralel dəyişiklikləri tam bloklayır.

Anomaliyaların qarşısını alma yolları

Isolation səviyyələri vs. Anomaliyalar

Isolation səviyyəsi Dirty Read Non-Repeatable Read Phantom Read
Read Uncommitted ❌ Bəli ❌ Bəli ❌ Bəli
Read Committed ✅ Xeyr ❌ Bəli ❌ Bəli
Repeatable Read ✅ Xeyr ✅ Xeyr ❌ Bəli
Serializable ✅ Xeyr ✅ Xeyr ✅ Xeyr

Doğru isolation səviyyəsini necə seçmək olar?

  1. Əgər məlumatlara tez çıxış lazımdır və anomaliyalar kritik deyil (məsələn, köhnəlmiş məlumatlar üzərində analitika üçün) — READ COMMITTED istifadə et.
  2. Əgər bir transaksiyanın içində məlumatın sabitliyi vacibdirsə — REPEATABLE READ istifadə et.
  3. Əgər maksimum izolasiya və konsistentlik lazımdırsa — SERIALIZABLE seç. Unutma: performans aşağı düşə bilər.

Praktiki tövsiyələr

Transaksiyaları sənin vəziyyətinə uyğun isolation səviyyəsi ilə istifadə et. Məsələn:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;
SELECT ...;
COMMIT;

İndekslər əlavə et ki, cədvəllərin bloklanmasını azaldasın və sorğular daha sürətli işləsin.

Optimallaşdırılmış sorğulardan istifadə et ki, uzunmüddətli bloklanmalardan qaçasan, xüsusilə SERIALIZABLE səviyyəsində.

Xüsusi səhvlər və onlardan necə qaçmaq olar

Bəzən düzgün seçilməmiş isolation səviyyəsi konfliktlərə və performansın aşağı düşməsinə səbəb olur. Məsələn, çoxlu paralel transaksiyaların olduğu sistemdə SERIALIZABLE istifadə etmək bloklanmalara və transaksiyaların "ac qalmasına" gətirib çıxara bilər.

Bundan qaçmaq üçün sorğularını analiz et, müxtəlif isolation səviyyələrində performansı test et və uyğun indekslərdən istifadə et.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION