İçeriğe geç

MVCC ve Kilitler — Eski Satır Sürümleri Nerede Yaşar?

İleri 9 dk Sık karşılaşılır

Önce şunu oku: İzolasyon Seviyeleri — Aynı İsim, Üç Farklı Davranış

30 saniyede özet

Biri bir satırı okurken başkası onu değiştiriyorsa iki yol var: ya okuyan bekler, ya da ona eski kopya gösterilir. Motorlar bu eski kopyaları farklı yerlerde saklar; uzun süren işler de her birinde başka bir sorun çıkarır.

Gece çalışan rapor bir gün dört saat sürdü. PostgreSQL’de ertesi sabah tablo diskte iki katına çıkmıştı. Oracle’daki kopyası ise raporu üçüncü saatte “snapshot too old” hatasıyla düşürmüştü.

  1. Bayt: Gece raporu bir gün dört saat sürdü. Ertesi sabah tablo diskte iki katına çıkmıştı!

  2. Sen: Rapor yalnızca okuyordu, değil mi?

  3. Bayt: Evet, sadece okuyordu. Okumak nasıl disk doldurur ki?

  4. Bayt: Biri belgeyi okurken başkası düzeltirse okuyan bekler mi, yoksa eski bir kopya mı alır?

Beklemek mi, eski kopya mı?

Bir transaction satırı güncelledi, henüz commit etmedi. Aynı satırı okumak isteyen sorgu SQL Server'ın varsayılan ayarında ve PostgreSQL'de ne yapar? Cevabı göster

SQL Server’da bekler, PostgreSQL’de beklemez. SQL Server’ın varsayılan READ COMMITTED’ı kilitle çalışır. PostgreSQL okuyana satırın commit edilmiş eski sürümünü gösterir.

Beklemek ya da eski kopyayı okumak; ikincisinin bir bedeli var.
Adım adım oku
  1. Kilit tabanlı modelde satır düzeltilirken okuyan, düzeltme commit edilene kadar bekler.
  2. MVCC'de okuyana satırın bir önceki sürümü hemen verilir; kimse beklemez.
  3. Eski sürümler, onları görebilecek bir okuma sürdükçe saklanmak zorundadır. Saatlerce açık kalan rapor, yığının büyümesine yol açar.
  4. Okuma bitince artık kimsenin görmediği sürümler temizlenir ve yer açılır.

Kilit modelinde veritabanı eski sürüm tutmaz; bedeli bekleme ve kilit zinciridir. Sürüm modelinde okuyan ve yazan birbirini beklemez; bedeli, eski sürümleri saklamak ve temizlemektir.

Multi
Çoklu:
Version
...sürüm. Bir satırın birden çok kopyası tutulur.
Concurrency
Eşzamanlılık: aynı anda çalışan işler...
Control
...kontrolü: okuyan eski kopyayı görür, yazanı beklemez.
Kafam karıştı, daha basit anlat

Biri defteri güncelliyorken sen okumak istiyorsun. Kilit modelinde yazmasının bitmesini beklersin. Sürüm modelinde ise sana defterin bir önceki fotokopisini verirler.

Hızlı kontrolOrta

Kilit tabanlı ve sürüm tabanlı (MVCC) eşzamanlılık arasındaki temel takas nedir?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Eski kopyalar nerede durur?

Eski sürüm neredeKim temizlerUzun sorgunun bedeli
PostgreSQLTablonun içinde, ölü satır olarakVACUUMTablo ve indeks şişer
OracleUndoSüresi dolunca yeniden kullanılırORA-01555 snapshot too old
SQL Server (RCSI)tempdb version storeArka plan temizliğitempdb büyür
SQL Server (varsayılan)Tutulmaz—Okuyucular bekler

PostgreSQL’de bir UPDATE, satırı yerinde değiştirmez; yeni bir sürüm yazar. Eskisini VACUUMPostgreSQL'in, hiçbir sorgunun artık göremeyeceği eski satır sürümlerini temizleyip alanı yeniden kullanılabilir yapan işlemi. Çoğunlukla autovacuum yürütür.Sözlükte gör → ancak hiçbir sorgu artık onu göremeyecekse siler.

Oracle satırı yerinde günceller ve eski değeri undoOracle'ın, güncellenen satırların eski değerlerini tuttuğu alan. Geri alma ve tutarlı okuma buradan yapılır; süresi dolan undo yeniden kullanılır.Sözlükte gör →’ya yazar. Uzun bir sorgu, çoktan başka işe verilmiş undo’ya ihtiyaç duyarsa hata alır.

Kafam karıştı, daha basit anlat

Eski fotokopiler bir yerde birikir. Kimse onlara bakmayacağı zaman temizlenirler. Uzun süre açık kalan bir iş, temizliği de bekletir.

Hızlı kontrolİleri

PostgreSQL'de sık güncellenen bir tablonun boyutu, satır sayısı değişmediği hâlde sürekli büyüyor. En olası sebep hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Oracle'da üç saat süren bir rapor sonunda `ORA-01555: snapshot too old` veriyor. Ne oldu?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendin gör

Eski satır sürümleri nerede yaşar, bedelini kim öder?

Tohum 434438

Oynat ya da adımla.

Saklanan eski sürümler

yok

Hız
Adım 0

Şu an ne oldu?

PostgreSQL: sıcak bir satır, iki güncelleme, bir okuyucu

Okuyucu, yazanı bekleyecek mi, eski bir sürümü mü görecek? Eski sürüm nerede duruyor?

Görevler0/3

  • Bir okuyucunun yazanı beklemesini sağlaaçık

    İpucu

    Eski sürüm tutmayan kurulum.

  • Uzun bir raporu ORA-01555 ile düşüraçık

    İpucu

    Undo, rapordan kısa ömürlü olsun.

  • PostgreSQL'de VACUUM'un eski sürümleri temizleyememesine yol açaçık

    İpucu

    Birinin hâlâ eski görüntüye ihtiyacı olsun.

Olay günlüğü (0)

Henüz olay yok. Oynat veya adımla.

  1. Varsayılanla oynat. PostgreSQL, uzun rapor: rapor tutarlı, ama VACUUM iki sürümü temizleyemedi.
  2. Okuyanı “kısa” yap. Temizlik geride kalmadı.
  3. Oracle seç, undo’yu “kısa” yap. Rapor en sonda ORA-01555 ile düştü.
  4. SQL Server (varsayılan) seç. Okuyucu bekledi; uzun rapor iki farklı anı karıştırdı.
  5. RCSI’yi aç. Bekleme bitti, eski sürümler tempdb’ye taşındı.
Hızlı kontrolİleri

Simülatörde SQL Server'ın varsayılan ayarında uzun rapor 'karışık zamanlı' oldu. Bu ne demek?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Uzun transaction’ı bul

Üç motorda da asıl düşman, açık kalan transaction’dır. Uygulama transaction açıp bir HTTP çağrısını beklerse, veritabanında idle in transaction bir oturum kalır.

  • PostgreSQL: pg_stat_activity içinde xact_start eski olan oturumlar; idle_in_transaction_session_timeout ayarı.
  • SQL Server: sys.dm_exec_requests içindeki blocking_session_id; RCSI açıksa sys.dm_tran_active_snapshot_database_transactions.
  • Oracle: V$TRANSACTION ve V$UNDOSTAT.

Gel, bunu bir bankanın havale servisinde görelim. Her transferden önce dış bir servise “bu işlem şüpheli mi?” diye soruluyor; tek fark, bu soruyu transaction’dan önce mi sonra mı sorduğumuz.

Derinleş · Havale servisi: kısa transaction 4 dosya · ~69 satır · ilk okumada atlayabilirsin
Proje dosyaları

src/main/java/com/bank/transfer/ TransferService.java Dış fraud kontrolü önce, transaction sonra; transaction yalnızca birkaç satır sürer.

src/main/java/com/bank/transfer/TransferService.java
@Service
class TransferService {
private final FraudClient fraud;
private final TransactionTemplate tx;
private final AccountRepository accounts;
TransferService(FraudClient fraud, TransactionTemplate tx, AccountRepository accounts) {
this.fraud = fraud;
this.tx = tx;
this.accounts = accounts;
}
TransferResult transfer(String fromIban, String toIban, BigDecimal amount, String currency) {
// The slow HTTP call runs first, while no transaction is open.
if (fraud.check(fromIban, toIban, amount, currency).rejected()) {
return TransferResult.REJECTED;
}
// The transaction starts only now and holds two UPDATEs.
return tx.execute(status -> {
// debit: UPDATE account SET balance = balance - :amount
// WHERE iban = :iban AND currency = :currency AND balance >= :amount
if (accounts.debit(fromIban, amount, currency) == 0) {
status.setRollbackOnly();
return TransferResult.INSUFFICIENT_FUNDS;
}
accounts.credit(toIban, amount, currency);
return TransferResult.BOOKED;
});
}
}

ops/postgres/ long-transactions.sql PostgreSQL'de uzun açık transaction'ı bulan sorgu ve boşta bekleyeni kapatan güvenlik ağı.

ops/postgres/long-transactions.sql
-- Oldest open transactions first; 'idle in transaction' is the usual suspect.
SELECT pid, application_name, state,
now() - xact_start AS xact_age,
left(query, 60) AS last_query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start
LIMIT 5;
-- Dead row versions on the ledger table, waiting for VACUUM.
SELECT relname, n_dead_tup, last_autovacuum
FROM pg_stat_user_tables
WHERE relname = 'account_movement';
-- Safety net: an idle open transaction of the transfer service is closed.
ALTER ROLE transfer_app SET idle_in_transaction_session_timeout = '30s';

ops/sqlserver/ rcsi.sql SQL Server'da RCSI'yi açmak ve eski sürümlerin tempdb'de ne kadar yer tuttuğuna bakmak.

ops/sqlserver/rcsi.sql
-- Readers stop waiting for writers: READ COMMITTED reads row versions instead.
ALTER DATABASE CoreBanking SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE;
-- The old versions now live in tempdb; this is where their size shows up.
SELECT DB_NAME(database_id) AS db, reserved_space_kb
FROM sys.dm_tran_version_store_space_usage;

counter-example/ SlowTransferService.java Şöyle de yazılabilirdi: fraud çağrısı transaction'ın içinde; bak, çağrı sürdükçe neler bekliyor.

counter-example/SlowTransferService.java
@Service
class SlowTransferService {
@Transactional // the transaction opens when the method starts
TransferResult transfer(String fromIban, String toIban, BigDecimal amount, String currency) {
accounts.debit(fromIban, amount, currency);
// While the fraud service thinks, this transaction keeps the debited account's
// row lock, keeps its snapshot open (VACUUM waits) and holds a pooled connection.
if (fraud.check(fromIban, toIban, amount, currency).rejected()) {
throw new TransferRejectedException(); // rolls back the debit
}
accounts.credit(toIban, amount, currency);
return TransferResult.BOOKED;
}
}
Hızlı kontrolİleri

Veritabanında sürekli 'idle in transaction' oturumlar görünüyor ve autovacuum geride kalıyor. Hatalı satır hangisi?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Hatalı satıra dokun, sonra kontrol et.

CheckoutService.java
Java 21UTF-8LF

Tuzaklar

Transaction içinde dış çağrı. @Transactional metodun içinden ödeme servisini çağırmak, çağrı süresince bağlantıyı ve eski sürümleri rehin tutar.

Autovacuum’u kapatmak. Şişme durmaz, yalnızca temizlik durur.

Replikada uzun rapor. PostgreSQL’de hot_standby_feedback açıksa replikadaki uzun sorgu, ana sunucudaki VACUUM’u da geride tutar.

lock escalationSQL Server'ın, tek bir işlemin tuttuğu çok sayıda satır ya da sayfa kilidini daha az sayıda tablo kilidine çevirmesi. Bellek kazandırır, eşzamanlılığı azaltır.Sözlükte gör →. SQL Server çok sayıda satır kilidini tablo kilidine yükseltebilir; büyük bir toplu güncelleme bütün tabloyu kilitleyebilir.

Hızlı kontrolUzman

PostgreSQL'de raporlar ana sunucuyu yormasın diye bir okuma replikasına taşındı ve `hot_standby_feedback` açıldı. Ana sunucuda şişme arttı. Neden?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

SQL Server'da bir gece işi milyonlarca satırı tek bir UPDATE ile güncellerken tüm tablo diğer kullanıcılara kilitleniyor. Olası sebep ve tipik çözüm?

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Kendini sına

Şimşek turu1/5

MVCC'de okuyanlar yazanları, yazanlar da okuyanları beklemez.

Soru 1/2İleri

Her belirtiyi ait olduğu motora yerleştir.

Cevabı biliyor musun?Önce birini seç. Tekrar zamanlaması buna göre ayarlanıyor.

Sınıflandırılmamış

PostgreSQL

Eski sürümler tabloda.

    Oracle

    Eski sürümler undo'da.

      SQL Server

      Varsayılan kilit; RCSI ile tempdb.

        Aklında kalacak üç şey

        1. 1 Kilit modelinde okuyan yazanı bekler; sürüm modelinde okuyan eski bir kopyayı görür ve kimse beklemez. Sürüm modeli beklemek yerine yer ve temizlikle öder.
        2. 2 PostgreSQL eski kopyaları tabloda tutar ve VACUUM ile temizler; Oracle undo alanında tutar; RCSI açık SQL Server tempdb'de tutar.
        3. 3 Uzun süren transaction'lar sürüm modelinde temizliği durdurur, Oracle'da 'snapshot too old' hatasına, kilit modelinde bekleme zincirlerine yol açar.
        Sonraki kapı Aynı SQL bir veritabanında çalışıyor, ötekinde hata veriyor. Hangisi haklı? Aynı Sorgu, Üç Lehçe — PostgreSQL, SQL Server, Oracle · 8 dk

        5 kart sonraki derste seni bekliyor

        0/5 kart bu dersten toplandı

        Bu dersin üstüne kurulanlar

        Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.