PostgreSQL'de kilitler, aynı veriye aynı anda erişen transaction'ların birbirini bozmasını engeller. Komutlar ihtiyaç duydukları kilidi kendiliğinden alır: SELECT tabloya en zayıf kip olan ACCESS SHARE kilidini, UPDATE ise tabloya ROW EXCLUSIVE ve değiştirdiği satırlara satır kilidi koyar. Kilitler transaction bitene kadar tutulur. Kendi kilit stratejinizi SELECT ... FOR UPDATE, LOCK TABLE ve advisory kilitlerle kurabilir, beklemeleri pg_locks ile izleyebilirsiniz.
Bu yazıda tablo ve satır kilit kiplerini, kuyruk tablosu için SKIP LOCKED kullanımını, NOWAIT ve lock_timeout ile beklemeyi sınırlamayı, deadlock'un nasıl oluştuğunu ve kimin kimi beklettiğini bulmayı, aynı anda çalışan psql oturumlarının gerçek çıktılarıyla gösteriyoruz. Okuma ve yazmanın birbirini neden çoğu zaman beklemediğini anlamak için önce MVCC ve izolasyon seviyeleri yazısını okumanız faydalı olur.
Kilitler ne zaman devreye girer?
MVCC sayesinde düz bir SELECT ile bir UPDATE birbirini beklemez. Kilitler asıl olarak iki yazma işlemi aynı satıra yöneldiğinde ve şema değiştiren komutlar tabloyu kullanılırken değiştirmeye çalıştığında hissedilir. Kılavuzun verdiği örnekle, TRUNCATE aynı tablo üzerindeki diğer işlemlerle güvenle eşzamanlı çalışamaz; bu yüzden tabloda ACCESS EXCLUSIVE kilidi alır ve o tabloya erişen herkesi bekletir.
Kilitleri görmek için pg_locks sistem görünümü kullanılır. Aşağıda açık bir transaction içinde tek bir satırı güncelledikten sonra kendi oturumumuzun kilitlerine bakıyoruz:
CREATE TABLE hesap (id int PRIMARY KEY, sahip text, bakiye numeric(12,2));
INSERT INTO hesap VALUES (1, 'Ayşe', 500), (2, 'Mehmet', 300);
BEGIN;
UPDATE hesap SET bakiye = bakiye - 10 WHERE id = 1;
SELECT locktype, relation::regclass AS nesne, mode, granted
FROM pg_locks
WHERE pid = pg_backend_pid()
ORDER BY locktype, relation::regclass::text;
ROLLBACK; locktype | nesne | mode | granted
---------------+------------+------------------+---------
relation | hesap | RowExclusiveLock | t
relation | hesap_pkey | RowExclusiveLock | t
relation | pg_locks | AccessShareLock | t
transactionid | | ExclusiveLock | t
virtualxid | | ExclusiveLock | t
(5 rows)Tablo ve indeksi üzerinde RowExclusiveLock görüyoruz; pg_locks sorgusunun kendisi de bu görünüm üzerinde AccessShareLock aldı. transactionid satırı ise transaction'ın kendi kimliği üzerindeki kilittir. Dikkat edin: güncellenen satırın kendisi listede yok. Kılavuz, PostgreSQL'in değiştirilen satırlar hakkında bellekte bilgi tutmadığını, bu yüzden aynı anda kilitlenebilecek satır sayısının sınırsız olduğunu belirtir. Satır kilidi satırın üzerine yazılır; bir oturum o satırı beklemeye başladığında ise pg_locks'ta bekleme kaydı olarak görünür. Bunu birazdan göreceğiz.
Tablo düzeyindeki kilit kipleri

Kılavuz sekiz tablo kilidi kipi tanımlar. Adlarında "ROW" geçenler de tablo kilididir; adlar tarihseldir ve kipler arasındaki tek gerçek fark hangi kiplerle çakıştıklarıdır. Bir transaction kendi kilitleriyle hiçbir zaman çakışmaz. Aşağıdaki tablo her kipi otomatik olarak alan komutları ve neyi engellediğini özetler:
| Kip | Otomatik alan komutlar | Çakıştığı kipler |
|---|---|---|
| ACCESS SHARE | SELECT | Yalnızca ACCESS EXCLUSIVE |
| ROW SHARE | SELECT FOR UPDATE / FOR SHARE ve benzerleri | EXCLUSIVE, ACCESS EXCLUSIVE |
| ROW EXCLUSIVE | INSERT, UPDATE, DELETE, MERGE | SHARE ve daha güçlü kipler |
| SHARE UPDATE EXCLUSIVE | VACUUM (FULL değil), ANALYZE, CREATE INDEX CONCURRENTLY, bazı ALTER TABLE biçimleri | Kendisi, SHARE ve daha güçlüler |
| SHARE | CREATE INDEX (CONCURRENTLY olmadan) | ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE ve SHARE ROW EXCLUSIVE ile üstü |
| SHARE ROW EXCLUSIVE | CREATE TRIGGER, bazı ALTER TABLE biçimleri | ROW EXCLUSIVE ve üstü, kendisi dahil |
| EXCLUSIVE | REFRESH MATERIALIZED VIEW CONCURRENTLY | ACCESS SHARE dışındaki tüm kipler |
| ACCESS EXCLUSIVE | DROP TABLE, TRUNCATE, REINDEX, CLUSTER, VACUUM FULL, çoğu ALTER TABLE, parametresiz LOCK TABLE | Tüm kipler |
Kılavuzun ipucu basittir: düz bir SELECT'i yalnızca ACCESS EXCLUSIVE engeller. Normal veri değişiklikleri (ROW EXCLUSIVE) birbiriyle çakışmaz; çakışma satır düzeyinde yaşanır. İndeks oluşturmanın kilit etkisi ve CONCURRENTLY seçeneği indeks türleri yazısında ayrıca ele alınıyor.
Satır kilitleri ve SELECT FOR UPDATE
Satır kilitleri okumayı etkilemez; yalnızca aynı satıra yazmak veya kilit almak isteyenleri bekletir. Dört satır kilidi kipi vardır ve SELECT sorgusunun sonuna kilit cümleciği eklenerek alınır:
| Satır kipi | Nasıl alınır | Neyi bekletir |
|---|---|---|
| FOR UPDATE | SELECT ... FOR UPDATE, DELETE, anahtar sütununu değiştiren UPDATE | Diğer tüm satır kilitlerini ve o satıra yazmayı |
| FOR NO KEY UPDATE | SELECT ... FOR NO KEY UPDATE, diğer UPDATE'ler | FOR KEY SHARE dışındaki tüm satır kilitlerini |
| FOR SHARE | SELECT ... FOR SHARE | Güncelleme ve silmeyi; diğer paylaşımlı kilitleri değil |
| FOR KEY SHARE | SELECT ... FOR KEY SHARE | Silmeyi ve anahtarı değiştiren güncellemeyi |
FOR UPDATE ile okunan satırlar, transaction bitene kadar başka transaction'lar tarafından değiştirilemez, silinemez veya kilitlenemez. Tipik kullanım "oku, kontrol et, sonra güncelle" akışıdır: bakiyeyi FOR UPDATE ile okuyan transaction, kontrolü yaparken başka birinin aynı bakiyeyi değiştirmeyeceğinden emin olur. FOR UPDATE sorgusu tabloya ROW SHARE kilidi de alır:
BEGIN;
SELECT * FROM hesap WHERE id = 2 FOR UPDATE;
SELECT locktype, relation::regclass AS nesne, mode, granted
FROM pg_locks
WHERE pid = pg_backend_pid() AND locktype = 'relation'
ORDER BY relation::regclass::text;
ROLLBACK; id | sahip | bakiye
----+--------+--------
2 | Mehmet | 300.00
(1 row)
locktype | nesne | mode | granted
----------+------------+-----------------+---------
relation | hesap | RowShareLock | t
relation | hesap_pkey | RowShareLock | t
relation | pg_locks | AccessShareLock | t
(3 rows)Kim kimi bekletiyor? pg_locks ve pg_blocking_pids
Şimdi gerçek bir bekleme üretelim. Üç oturumu aynı anda başlattık: A bir satırı güncelleyip üç saniye bekliyor, B yarım saniye sonra aynı satırı güncellemeye çalışıyor, C ise 1,5 saniyede durumu inceliyor:
-- Oturum A
BEGIN;
UPDATE hesap SET bakiye = bakiye - 50 WHERE id = 1;
SELECT pg_sleep(3);
COMMIT;
-- Oturum B
SELECT pg_sleep(0.5);
UPDATE hesap SET bakiye = bakiye + 50 WHERE id = 1;
-- Oturum C
SELECT pg_sleep(1.5);
SELECT pid, pg_blocking_pids(pid) AS engelleyen, wait_event_type, wait_event, state, left(query, 45) AS sorgu
FROM pg_stat_activity
WHERE datname = 'ornek_kilit' AND pid <> pg_backend_pid()
ORDER BY backend_start;
SELECT l.pid, l.locktype, l.mode, l.granted
FROM pg_locks l
WHERE NOT l.granted;-- Oturum C
pid | engelleyen | wait_event_type | wait_event | state | sorgu
-------+------------+-----------------+---------------+--------+-----------------------------------------------
96404 | {92968} | Lock | transactionid | active | UPDATE hesap SET bakiye = bakiye + 50 WHERE i
92968 | {} | Timeout | PgSleep | active | SELECT pg_sleep(3);
(2 rows)
pid | locktype | mode | granted
-------+---------------+-----------+---------
96404 | transactionid | ShareLock | f
(1 row)B'nin süreci (96404) Lock türünde bekliyor ve pg_blocking_pids onu bekleten sürecin A (92968) olduğunu söylüyor. pg_locks'ta görülen ayrıntı da öğreticidir: B satırın kendisini değil, A'nın transaction kimliğini ShareLock kipinde istiyor, yani "A bitsin" diye bekliyor. A commit edince B'nin UPDATE komutu tamamlandı. Kılavuz pg_blocking_pids için iki uyarı yapar: sonuç, kilidi tutanları (sert engel) ve kuyrukta önde bekleyen çakışan istekleri (yumuşak engel) birlikte içerir; sık çağrılması da kilit yöneticisine kısa süreli özel erişim gerektirdiği için performansı etkileyebilir. Bekleyen bir oturumu iptal etme ve uzun sorguları bulma yöntemleri pg_stat_activity yazısında anlatılıyor.
Beklemeyi sınırlamak: NOWAIT, SKIP LOCKED ve lock_timeout

Bir kilit çakışması olduğunda PostgreSQL, deadlock tespit edilmediği sürece süresiz bekler. Kılavuz bu yüzden uygulamaların transaction'ları uzun süre, örneğin kullanıcı girdisi beklerken, açık tutmamasını önerir. Beklemeyi kontrol etmenin üç yolu vardır:
- NOWAIT: Satır hemen kilitlenemiyorsa beklemek yerine hata verilir.
- SKIP LOCKED: Hemen kilitlenemeyen satırlar sonuçtan atlanır.
- lock_timeout: Herhangi bir kilidi bekleme süresine üst sınır koyar; süre dolunca komut iptal edilir.
SKIP LOCKED, birden çok işçinin aynı iş kuyruğundan iş çektiği senaryolar için tasarlanmıştır. Kılavuz, atlanan satırlar yüzünden verinin tutarsız bir görüntüsü elde edildiğini, bu yüzden genel amaçlı sorgular için uygun olmadığını özellikle belirtir. Aşağıda A ve B aynı kuyruktan ilk bekleyen işi alıyor:
CREATE TABLE gorev (id int PRIMARY KEY, is_adi text, durum text DEFAULT 'bekliyor');
INSERT INTO gorev (id, is_adi) VALUES (1, 'fatura gönder'), (2, 'e-posta at'), (3, 'rapor üret');
-- Oturum A
BEGIN;
SELECT id, is_adi FROM gorev WHERE durum = 'bekliyor' ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED;
SELECT pg_sleep(2);
UPDATE gorev SET durum = 'bitti' WHERE id = 1;
COMMIT;
-- Oturum B (yarım saniye sonra)
\set VERBOSITY verbose
BEGIN;
SELECT id, is_adi FROM gorev WHERE durum = 'bekliyor' ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED;
COMMIT;
BEGIN;
SELECT * FROM gorev WHERE id = 1 FOR UPDATE NOWAIT;
ROLLBACK;
SET lock_timeout = '500ms';
UPDATE gorev SET durum = 'iptal' WHERE id = 1;-- Oturum A
BEGIN
id | is_adi
----+---------------
1 | fatura gönder
(1 row)
UPDATE 1
COMMIT
-- Oturum B
BEGIN
id | is_adi
----+------------
2 | e-posta at
(1 row)
COMMIT
BEGIN
ERROR: 55P03: could not obtain lock on row in relation "gorev"
LOCATION: heap_lock_tuple, heapam.c:5027
ROLLBACK
SET
ERROR: 55P03: canceling statement due to lock timeout
CONTEXT: while updating tuple (0,1) in relation "gorev"
LOCATION: ProcessInterrupts, postgres.c:3438Çıktıdaki pg_sleep satırlarını kısalık için çıkardık. A birinci işi kilitledi; B aynı sorguyla beklemeden ikinci işi aldı. Kilitli birinci satırı NOWAIT ile istemek hemen 55P03 (lock_not_available) hatası verdi; lock_timeout ile yapılan UPDATE ise yarım saniye bekleyip aynı kodla iptal edildi. Bu iki seçeneğin farkı, hatanın ne zaman geldiğidir: NOWAIT hiç beklemez, lock_timeout belirlediğiniz süre kadar bekler. Kılavuza göre NOWAIT ve SKIP LOCKED yalnızca satır kilitlerine uygulanır; gereken ROW SHARE tablo kilidi yine normal şekilde alınır. Tablo kilidini de beklemeden almak istiyorsanız önce LOCK TABLE ... NOWAIT kullanabilirsiniz.
Deadlock nasıl oluşur ve nasıl önlenir?
Deadlock, iki veya daha fazla transaction'ın her birinin diğerinin istediği kilidi tutmasıdır. Açık kilit kullanmasanız da satır kilitleri yüzünden oluşabilir. Kılavuzdaki örneği iki havaleyle tekrarladık: A önce 1, sonra 2 numaralı hesabı güncelliyor; B aynı anda önce 2, sonra 1 numaralı hesabı güncelliyor:
-- Oturum A
\set VERBOSITY verbose
BEGIN;
UPDATE hesap SET bakiye = bakiye - 100 WHERE id = 1;
SELECT pg_sleep(1);
UPDATE hesap SET bakiye = bakiye + 100 WHERE id = 2;
COMMIT;
-- Oturum B
\set VERBOSITY verbose
BEGIN;
UPDATE hesap SET bakiye = bakiye - 100 WHERE id = 2;
SELECT pg_sleep(1);
UPDATE hesap SET bakiye = bakiye + 100 WHERE id = 1;
COMMIT;-- Oturum A
BEGIN
UPDATE 1
ERROR: 40P01: deadlock detected
DETAIL: Process 88464 waits for ShareLock on transaction 990; blocked by process 24304.
Process 24304 waits for ShareLock on transaction 989; blocked by process 88464.
HINT: See server log for query details.
CONTEXT: while updating tuple (0,2) in relation "hesap"
LOCATION: DeadLockReport, deadlock.c:1138
ROLLBACK
-- Oturum B
BEGIN
UPDATE 1
UPDATE 1
COMMITPostgreSQL döngüyü tespit etti ve transaction'lardan birini (bu denemede A'yı) 40P01 hatasıyla iptal etti; B işini tamamladı. Kılavuz, hangi transaction'ın iptal edileceğinin önceden kestirilemeyeceğini ve buna güvenilmemesi gerektiğini belirtir. A'nın COMMIT komutunun ROLLBACK döndürdüğüne de dikkat edin. Hata ayrıntısındaki ipucu doğru: sunucu günlüğünde sorgular da yazıyordu:
2026-11-07 12:34:16.804 +03 [88464] ERROR: deadlock detected
2026-11-07 12:34:16.804 +03 [88464] DETAIL: Process 88464 waits for ShareLock on transaction 990; blocked by process 24304.
Process 24304 waits for ShareLock on transaction 989; blocked by process 88464.
Process 88464: UPDATE hesap SET bakiye = bakiye + 100 WHERE id = 2;
Process 24304: UPDATE hesap SET bakiye = bakiye + 100 WHERE id = 1;Deadlock kontrolü pahalı olduğu için sunucu bunu her beklemede yapmaz; bir kilidi deadlock_timeout kadar (varsayılan 1 saniye) bekledikten sonra kontrol eder. log_lock_waits açıksa aynı süreyi aşan kilit beklemeleri de günlüğe yazılır. Kılavuzun önleme önerileri şunlardır:
- Birden çok nesneyi kilitleyen bütün uygulamalar kilitleri aynı sırayla almalıdır. Örnekte iki havale de önce küçük numaralı hesabı güncelleseydi deadlock oluşmazdı.
- Bir nesne üzerinde alınan ilk kilit, o nesne için gerekecek en kısıtlayıcı kip olmalıdır. Önce zayıf kilit alıp sonra yükseltmek deadlock riskini artırır.
- Bunu önceden garanti edemiyorsanız deadlock nedeniyle iptal edilen transaction'ları yeniden deneyin.
LOCK TABLE ve kilit kuyruğu tuzağı
LOCK TABLE komutu tablo kilidini açıkça alır. Kip belirtilmezse en kısıtlayıcı kip olan ACCESS EXCLUSIVE kullanılır. UNLOCK TABLE diye bir komut yoktur; kilit transaction bitince bırakılır, bu yüzden komut yalnızca transaction bloğu içinde çalışır. Kılavuzun örneklerinden biri, READ COMMITTED seviyesinde bir tablonun transaction boyunca değişmemesi gerektiğinde SHARE kipinin kullanılmasıdır; tabloyu değiştirecek bir transaction ise iki oturumun aynı anda SHARE alıp ardından birbirini kilitlemesini önlemek için SHARE ROW EXCLUSIVE almalıdır.
Üretimde sık yaşanan bir sorun da şema değişikliğinin kuyruğa girmesidir. Aşağıda A uzun bir okuma transaction'ı açık tutuyor. B yarım saniye sonra bir sütun eklemek istiyor; ALTER TABLE ACCESS EXCLUSIVE gerektirdiği için A'yı bekliyor. C bir saniyede sıradan bir SELECT count(*) çalıştırıyor:
-- Oturum A
BEGIN;
SELECT count(*) FROM hesap;
SELECT pg_sleep(3);
COMMIT;
-- Oturum B
SELECT pg_sleep(0.5);
ALTER TABLE hesap ADD COLUMN not_alani text;
-- Oturum C
SELECT pg_sleep(1);
SET lock_timeout = '1s';
SELECT count(*) FROM hesap;-- Oturum B
ALTER TABLE
-- Oturum C
SET
ERROR: canceling statement due to lock timeout
LINE 1: SELECT count(*) FROM hesap;
^C'nin SELECT sorgusu A ile çakışmıyordu; ancak kuyrukta kendisinden önce bekleyen B'nin ACCESS EXCLUSIVE isteğiyle çakıştığı için o da bekledi ve bir saniyelik zaman aşımına takıldı. pg_blocking_pids açıklamasındaki "yumuşak engel" tam olarak budur. Gerçek bir sistemde bu, tek bir ALTER TABLE yüzünden tablonun bütün okumalarının durması anlamına gelir. Şema değişikliğini çalıştırmadan önce oturumunuzda kısa bir lock_timeout ayarlamak, kilidi alamadığında komutun kuyrukta beklemek yerine hata verip çekilmesini sağlar; sonra yeniden deneyebilirsiniz. Tablo değişikliklerinin kendisi CREATE TABLE ve ALTER TABLE yazısında anlatılıyor.
Advisory kilitler
Advisory kilitler anlamı uygulama tarafından belirlenen kilitlerdir; veritabanı onları hiçbir tabloya bağlamaz, doğru kullanmak uygulamanın sorumluluğundadır. Örneğin aynı zamanlanmış görevin iki sunucuda aynı anda çalışmasını engellemek için bir sayıyı kilit anahtarı olarak kullanabilirsiniz. Kılavuza göre bir tabloda bayrak tutmaya göre daha hızlıdır, tablo şişmesine yol açmaz ve oturum bitince sunucu tarafından kendiliğinden temizlenir.
İki türü vardır. Oturum düzeyindeki kilit (pg_advisory_lock, pg_try_advisory_lock) açıkça bırakılana ya da oturum bitene kadar tutulur ve transaction kurallarına uymaz: geri alınan bir transaction içinde alınmış olsa bile kalır. Transaction düzeyindeki kilit (pg_advisory_xact_lock, pg_try_advisory_xact_lock) transaction bitince kendiliğinden bırakılır ve ayrı bir bırakma komutu yoktur:
-- Oturum A
SELECT pg_try_advisory_lock(42) AS alindi;
SELECT pg_sleep(1.5);
SELECT pg_advisory_unlock(42) AS birakildi;
SELECT pg_advisory_unlock(42) AS birakildi;
-- Oturum B (yarım saniye sonra)
SELECT pg_try_advisory_lock(42) AS alindi;
SELECT locktype, objid, mode, granted FROM pg_locks WHERE locktype = 'advisory';
SELECT pg_sleep(1.5);
BEGIN;
SELECT pg_try_advisory_xact_lock(42) AS alindi;
COMMIT;-- Oturum A
alindi
--------
t
(1 row)
birakildi
-----------
t
(1 row)
WARNING: you don't own a lock of type ExclusiveLock
birakildi
-----------
f
(1 row)
-- Oturum B
alindi
--------
f
(1 row)
locktype | objid | mode | granted
----------+-------+---------------+---------
advisory | 42 | ExclusiveLock | t
(1 row)
BEGIN
alindi
--------
t
(1 row)
COMMITtry ile başlayan sürümler beklemez, kilidi alamazsa false döner. Sahip olmadığınız bir kilidi bırakmaya çalışmak uyarı ve false üretir. Aynı oturum bir kilidi birden çok kez alabilir; kılavuza göre her başarılı alma için ayrı bir bırakma gerekir. Advisory ve normal kilitler aynı paylaşılan bellek havuzunu kullandığı için sayıları sınırsız değildir. LIMIT içeren sorgularda kilit fonksiyonunu doğrudan seçim listesine koymak tehlikelidir, çünkü LIMIT'in kilitlemeden önce uygulanacağı garanti edilmez; kılavuz bu durumda kilidi bir alt sorgunun sonucu üzerinde almayı önerir.
Sık yapılan hatalar

- Kullanıcı yanıtını beklerken transaction'ı açık tutmak: Alınan kilitler sonuna kadar tutulur. Zaman aşımı ayarları için transaction yazısındaki tabloya bakın.
- Kilitleri farklı sırayla almak: Deadlock'un en yaygın nedenidir. Toplu güncellemelerde satırları birincil anahtara göre sıralı işleyin.
- Yoğun tabloda zaman aşımı olmadan ALTER TABLE çalıştırmak: Kilit kuyruğu bütün okumaları durdurabilir.
- SKIP LOCKED'ı rapor sorgularında kullanmak: Kilitli satırlar sessizce atlanır, sonuç eksik olur.
- Oturum düzeyi advisory kilidi bırakmayı unutmak: Bağlantı havuzu kullanan uygulamalarda oturum uzun yaşadığı için kilit beklenenden çok uzun kalabilir.
Sık Sorulan Sorular
SELECT sorgusu UPDATE'i bekletir mi?
Hayır. Düz SELECT yalnızca ACCESS SHARE alır ve bu kip sadece ACCESS EXCLUSIVE ile çakışır. Okuma ve yazma MVCC sayesinde birbirini beklemez.
Bir tabloyu kilidini nasıl açarım?
Açamazsınız; UNLOCK TABLE komutu yoktur. Tablo ve satır kilitleri transaction bitince (veya kilit alındıktan sonra konmuş bir savepoint'e geri dönülünce) bırakılır.
NOWAIT ile lock_timeout arasındaki fark nedir?
NOWAIT hiç beklemeden hata verir ve yalnızca o komuttaki satır veya tablo kilidine uygulanır. lock_timeout ise oturumdaki her kilit isteğine uygulanan bir üst sınırdır; ikisi de 55P03 koduyla döner.
Deadlock hatası alınca ne yapmalıyım?
İptal edilen transaction'ı baştan yeniden çalıştırın ve kodunuzda kilitlerin hep aynı sırayla alınmasını sağlayın. Hata kodu 40P01'dir; ayrıntılar için SQLSTATE kodları yazısına bakabilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · İzolasyon seviyeleri ve MVCC · Transaction ve SAVEPOINT · pg_stat_activity ile izleme · İndeks türleri