PostgreSQL, bölümlenmiş bir tabloya yapılan başvurunun fiziksel bölümleri arasında da çalışması gerektiği için ek yabancı anahtar katalog satırları oluşturur. Bu satırların tek bir ilişkiyi mi yoksa ayrı bildirimleri mi temsil ettiğini belirlemek için üst bağlantılarını ve başvurulan tabloları inceleyin.
Bu adım adım kılavuz, bir veritabanı tarayıcısında veya Node.js uygulamasında beklenmedik bir kısıt listesi araştıran Mac kullanan geliştiriciler içindir. Amaç, sentetik makale satırlarıyla davranışı yeniden oluşturmak, kısıt ailesinin izini sürmek ve mantıksal şema raporunda nelerin yer alması gerektiğine karar vermektir.
Bir yabancı anahtar neden birden fazla kısıt satırı oluşturur?
Bölümlenmiş bir tablo, satırları bölümlerinde saklanan mantıksal bir tablo sunar. Üst tablonun kendi depolama alanı yoktur. Başka bir tablo ona başvurduğunda bu ayrım önem kazanır: PostgreSQL, fiziksel bölümlerdeki satırlar değiştiğinde ilişkinin korunmasını sağlamalıdır. Resmî Tablo Bölümleme belgelerine bakın.
PostgreSQL 18’in uygulaması bu mekanizmayı açıkça gösterir. addFkRecurseReferenced yordamı yabancı anahtar eylem tetikleyicileri oluşturur ve başvurulan her bölüm için yinelemeli olarak ek bir pg_constraint satırı oluşturur. Doğrulama kodu, başvurulan taraftaki bu satırların ayrı doğrulama taramaları yerine eylem tetikleyicilerini desteklediğini açıklar. PostgreSQL’in yabancı anahtar oluşturma ve doğrulama uygulamasına bakın.
Dolayısıyla bu satırlar, başvuran her değerin her bölümde bulunması gerektiği anlamına gelmez. Bildirilen ilişki yine bölümlenmiş üst tabloyu hedefler. PostgreSQL’in, başvurulan bir satır silindiğinde veya anahtarı değiştiğinde yapılandırılmış davranış da dâhil olmak üzere, başvurulan taraftaki değişiklikleri de ele alması gerekir. Bu davranışlar Yabancı Anahtarlar bölümünde açıklanmıştır.
Hangi PostgreSQL sürümleri bunu destekler?
Bölümlenmiş bir tabloya başvuran yabancı anahtarlar PostgreSQL 12’de kullanıma sunuldu. Daha eski sürümlerde aynı üst tabloyu hedefleyen bildirim kullanılamaz. PostgreSQL 12 artık desteklenmeyen sürümler arasında listeleniyor; bu sürüm önerilen bir kurulum hedefi değil, özelliğin tarihsel başlangıç noktasıdır. Bu makalede güncel PostgreSQL 18 belgeleri ve bakımı sürdürülen kaynak dalı kullanılıyor. PostgreSQL 12 sürüm notlarına bakın.
Sentetik makale satırlarıyla ilişkiyi yeniden oluşturun
Mevcut bir yerel PostgreSQL geliştirme veritabanını ve çalışan bir psql kurulumunu kullanın. Mac’inizde Terminal’i açın, psql -d postgres ile bağlanın ve sunucuyu SHOW server_version; komutuyla denetleyin. Gerekirse geliştirme veritabanınızın adını kullanın. Resmî psql belgeleri, veritabanı seçimini ve etkileşimli SQL yürütmeyi açıklar.
Bu tam kurulum komutlarını bir kez çalıştırın. Mevcut nesneleri silmeden özel bir şema oluşturur. Bu şema zaten varsa durun ve yeni bir geliştirme veritabanı kullanın ya da örneklerin tamamında şemanın adını tutarlı biçimde değiştirin.
BEGIN;
CREATE SCHEMA fk_partition_demo;
CREATE TABLE fk_partition_demo.articles (
article_id integer NOT NULL,
publication_year integer NOT NULL,
title text NOT NULL,
PRIMARY KEY (article_id, publication_year)
) PARTITION BY RANGE (publication_year);
CREATE TABLE fk_partition_demo.articles_2025
PARTITION OF fk_partition_demo.articles
FOR VALUES FROM (2025) TO (2026);
CREATE TABLE fk_partition_demo.articles_2026
PARTITION OF fk_partition_demo.articles
FOR VALUES FROM (2026) TO (2027);
CREATE TABLE fk_partition_demo.article_notes (
note_id integer PRIMARY KEY,
article_id integer NOT NULL,
publication_year integer NOT NULL,
note_text text NOT NULL,
CONSTRAINT article_notes_article_fk
FOREIGN KEY (article_id, publication_year)
REFERENCES fk_partition_demo.articles
(article_id, publication_year)
);
INSERT INTO fk_partition_demo.articles
(article_id, publication_year, title)
VALUES
(101, 2025, 'A guide to paper models'),
(102, 2026, 'Choosing a notebook layout');
INSERT INTO fk_partition_demo.article_notes
(note_id, article_id, publication_year, note_text)
VALUES
(1, 101, 2025, 'Add a materials list'),
(2, 102, 2026, 'Include a grid example');
COMMIT;
Bileşik birincil anahtar bilerek kullanılmıştır. PostgreSQL, bölümlenmiş bir tablonun birincil veya benzersiz kısıtının her bölümleme anahtarı sütununu içermesini ve bölümleme anahtarlarındaki ifadelerle ilgili ek kısıtlamalara uymasını gerektirir. Bu tablo publication_year sütununa göre bölümlendiği için birincil anahtar bu sütunu içerir ve yabancı anahtar çiftin tamamına başvurur. Bildirime Dayalı Bölümleme: Kısıtlamalar bölümüne bakın.
Bu nedenle örnek, bir makaleyi (article_id, publication_year) ile tanımlar. article_id değerinin tek başına genel olarak benzersiz olduğunu göstermez. Uygulamanız yalnızca article_id kullanarak başvuru yapmayı gerektiriyorsa bu örneği benimsemeden önce bölümleme ve anahtar tasarımını yeniden değerlendirin.
Adları karşılaştırmak yerine kısıt ailesinin izini sürün
Katalogdaki yararlı alanlar şunlardır: başvuran tablo olan conrelid; başvurulan tablo olan confrelid; ve üst kısıtın OID’si olan conparentid. Kısıt adlarının benzersiz olması gerekmez, bu nedenle yalnızca adlara bakarak iki satırın bağımsız olup olmadığı belirlenemez. Bu alanlar pg_constraint içinde belgelenmiştir.
Kurulumu çalıştırdıktan sonra bu sorguyu yürütün. article_notes üzerinde bildirilen kök yabancı anahtarlarla başlar ve alt kısıtlarını yinelemeli olarak izler.
WITH RECURSIVE fk_family AS (
SELECT c.oid, c.conparentid, c.oid AS root_oid, 0 AS depth
FROM pg_catalog.pg_constraint AS c
WHERE c.contype = 'f'
AND c.conrelid =
'fk_partition_demo.article_notes'::regclass
AND c.conparentid = 0
UNION ALL
SELECT child.oid, child.conparentid,
parent.root_oid, parent.depth + 1
FROM pg_catalog.pg_constraint AS child
JOIN fk_family AS parent
ON child.conparentid = parent.oid
WHERE child.contype = 'f'
)
SELECT
family.root_oid,
family.depth,
c.oid AS constraint_oid,
c.conname,
c.conparentid,
c.conrelid::regclass AS referencing_table,
c.confrelid::regclass AS referenced_table,
pg_get_constraintdef(c.oid) AS definition
FROM fk_family AS family
JOIN pg_catalog.pg_constraint AS c ON c.oid = family.oid
ORDER BY family.root_oid, family.depth, c.oid;
Bu tek seviyeli örnekte, uygulamanın öngördüğü sonuç üç yabancı anahtar satırıdır: biri articles tablosunu, diğer ikisi de onun iki bölümünü hedefler. Bu, yakalanmış bir yürütme çıktısı değil, kaynak koddan çıkarılan beklenen sonuçtur. Oluşturulan adlar ve OID değerleri sabit kodlanmamalıdır. Aynı kaynak, bir bölüm daha sonra oluşturulduğunda veya eklendiğinde başvurulan tarafta da kısıtlar oluşturur. tablecmds.c dosyasına bakın.
| Bu örnekteki satır | Başvuran tablo | Başvurulan tablo | Üst bağlantısı |
|---|---|---|---|
| Kök ilişki | article_notes |
articles |
conparentid = 0 |
| Başvurulan bölüm alt satırı | article_notes |
articles_2025 |
Kök kısıtın OID’si |
| Başvurulan bölüm alt satırı | article_notes |
articles_2026 |
Kök kısıtın OID’si |
Kolayca gözden kaçan ayrıntı, üç satırın tamamında başvuran tablonun article_notes olarak kalmasıdır. Her iki tablo sütununu ve üst bağlantısını inceleyin; yalnızca kısıtla ilişkili tabloya bakmak, başvurulan bölüm yapısını gizleyebilir.
Sorgu ayrıca pg_get_constraintdef() aracılığıyla yeniden oluşturulmuş tanımları gösterir. PostgreSQL bu işlevi, gönderilen özgün SQL’in aynısı değil, yeniden oluşturulmuş bir tanım olarak belgeler. İlişkiyi anlamak için kullanın; özgün geçiş betiğini geri elde etmek için kullanmayın. Sistem Bilgisi İşlevleri ve İşleçleri bölümüne bakın.
Aynı satırları Mac’inizde node-postgres ile inceleyin
node-postgres, sunucunun sorgu sonuçlarını döndürür; bölümlemeyle ilgili satırlar PostgreSQL’in kısıt mekanizmasından kaynaklanır. Belgelenmiş sorgu API’si SQL metnini ve parametre değerlerinden oluşan ayrı bir diziyi kabul eder. Burada ilişki adı, PostgreSQL tarafından regclass türüne dönüştürülen bir metin değeri olarak iletilir. Sorgular bölümüne bakın.
Güncel ve desteklenen bir Node.js sürümü kurulu olduğunda bir çalışma dizini oluşturun ve pg paketini yükleyin. Kurulum komutu ve çalışma zamanı uyumluluğu yönergeleri node-postgres girişinde yer alır.
mkdir pg-fk-inspection
cd pg-fk-inspection
npm init -y
npm install pg
Aşağıdaki tam programı inspect-fks.mjs adıyla kaydedin. Yukarıdaki SQL kurulumunun kaydedilmiş olmasını gerektirir. Özyinelemeli SQL raporundan farklı olarak bu program, verilen başvuran tabloya doğrudan bağlı satırları listeler; bu örnekteki bölümlenmemiş article_notes tablosu için bu yeterlidir.
import pg from 'pg';
const { Client } = pg;
const client = new Client({ connectionTimeoutMillis: 5000 });
const relation = process.argv[2] ??
'fk_partition_demo.article_notes';
try {
await client.connect();
const version = await client.query('SHOW server_version');
console.log('PostgreSQL:', version.rows[0].server_version);
const result = await client.query(`
SELECT oid, conname,
conrelid::regclass::text AS referencing_table,
confrelid::regclass::text AS referenced_table,
conparentid,
conparentid = 0 AS is_root,
pg_get_constraintdef(oid) AS definition
FROM pg_catalog.pg_constraint
WHERE contype = 'f' AND conrelid = $1::regclass
ORDER BY conparentid, oid
`, [relation]);
console.table(result.rows);
} catch (error) {
console.error(error.message);
process.exitCode = 1;
} finally {
await client.end();
}
Programı SQL kurulumu için kullandığınız aynı veritabanına karşı çalıştırın. node-postgres, Bağlanma bölümünde varsayılanları belgelenen PGDATABASE dâhil PostgreSQL bağlantı ortam değişkenlerini kullanır.
PGDATABASE=postgres node inspect-fks.mjs
İlişki bulunamazsa her iki oturumun da aynı veritabanını kullandığını ve kurulumun başarıyla tamamlandığını doğrulayın. Boş sonuç, bu sorgunun ilişkiye doğrudan bağlı yabancı anahtar bulamadığı anlamına gelir; diğer tablolardan gelen başvuruları raporlamaz. Bu makalenin hazırlığı sırasında JavaScript için sözdizimi denetimi yapıldı. Veritabanında yürütme olanağı yoktu; bu nedenle SQL örnekleri ve beklenen katalog yapısı, alınan belgeler ve kaynak kodla karşılaştırılarak incelendi.
Neleri göstereceğinize veya inceleyeceğinize karar verin
Bir kısıt listesi beklenenden uzun göründüğünde aşağıdaki sırayı izleyin. Bu adımlar, yararlı kanıtları kaybetmeden mantıksal ilişki raporuyla uygulama envanterini birbirinden ayırır.
- İlişkiyi ve sunucu sürümünü doğrulayın. Belgelenmiş davranışla karşılaştırma yapmadan önce şema nitelemeli ilişki adını kullanın ve
SHOW server_version;çıktısını kaydedin. - Üst bağlantılarını izleyin. Bu örnekte aynı kök OID’yi paylaşan alt satırlar, bildirilen ilişkinin kısıt ailesine aittir.
- İki tarafı da karşılaştırın. Başvuran tablo aynı kalırken
confreliddeğerinin değişmesi, yukarıda gösterilen başvurulan bölüm satırlarını açıklar. - Raporun amacını belirleyin. Seçilen tabloda bildirilen kök ilişkiler için
contype = 'f' AND conparentid = 0ile filtreleyin. Tam bir aile raporu için özyinelemeli raporu koruyun. - Ayrı kökleri tek tek inceleyin. İki bildirimin gereksiz olduğuna karar vermeden önce sütun çiftlerini, başvurulan tabloları, eylemleri, doğrulama durumunu ve ertelenebilirlik özelliğini karşılaştırın.
Bu raporlama yaklaşımı, pg_constraint içinde belgelenen tanımlayıcıları ve ilişki alanlarını kullanır. Yalnızca kökleri gösteren filtre bilerek dar kapsamlı tutulmuştur: bir bölüm, devralınan alt kısıtlar aracılığıyla ilişkiye katılabilir; bu nedenle bir yaprak tabloyu köklerle filtrelemek, onu etkileyen tüm ilişkileri eksiksiz biçimde raporlamaz.
Zorlamayı sağlayan nesnelerin kanıtına ihtiyacınız varsa pg_trigger.tgconstraint bir tetikleyiciyi kısıtına, tgrelid ise tetikleyiciyi taşıyan tabloya bağlar. Katalog, sistem tarafından oluşturulan tetikleyicileri de tanımlar. Bu alanlar, pg_trigger üzerinden ek bir inceleme yolu sunar.
Bildirilen ilişki hâlâ gerekliyse oluşturulan satırları koruyun. Yeniden oluşturulan örnek için pratik çözüm, mantıksal şema görünümünde kök ilişkiyi göstermek ve alt satırları tanılama görünümünde tutmaktır. Üst bağlantıları ve tabloların her iki ucunu da görünür kıldığınızda ek satırlar, PostgreSQL’in bölümler genelinde başvuruyu nasıl uyguladığını açıklar.
Kaynaklar
Tablo Bölümleme — PostgreSQL Global Development Group.
pg_constraint — PostgreSQL Global Development Group.
Sürüm 12 — PostgreSQL Global Development Group.
tablecmds.c, REL_18_STABLE — PostgreSQL Global Development Group.
Kısıtlar — PostgreSQL Global Development Group.
psql — PostgreSQL Global Development Group.
Sistem Bilgisi İşlevleri ve İşleçleri — PostgreSQL Global Development Group.
pg_trigger — PostgreSQL Global Development Group.
node-postgres’e Giriş — node-postgres.
Sorgular — node-postgres.
Bağlanma — node-postgres.