Boş olmayan alanlar için PostgreSQL'de NOT NULL belirtmemenin sonuçları nelerdir?


10

Tablolarda alanların çoğunluğu her zaman boş olmayan bir uygulama (veri PostgreSQL saklanır) var, ama bu tablolar için şema bunu zorlamıyor. Örneğin şu sahte tabloya bakın:

CREATE TABLE "tbl" (
    "id" serial,
    "name" varchar(40),
    "num" int,
    "time" timestamp
    PRIMARY KEY ("id"),
    UNIQUE ("id")
);

Ayrıca name, num, timeaçıkça olarak belirtilmeyen NOT NULLoldukları gerçeklik içinde icra uygulama tarafında olur, çünkü.


Benim düşüncem, değiştirilmesi gerektiğidir, ancak kontrpuan, uygulama seviyesinin boş değerlerin burada görünemediğinden ve başka hiç kimse tabloyu manuel olarak değiştirmediğinden emin olmasıdır.

Benim sorum : Avantajları (performans, depolama, tutarlılık, başka bir şey) ve dezavantajları (şu anda hiç boş değer olmadığını doğruladığımı varsayarak ve iş mantığından boş olmamalı) varsayarak açık NOT NULLkısıtlama?

İyi bir kod inceleme sürecine ve oldukça iyi bir dokümantasyona sahibiz, bu nedenle bazı yeni kişilerin bu kısıtlamayı ihlal eden bir şey yapma olasılığı gerçekten değişikliği haklı çıkarmak için yeterli değildir.

Bu benim kararım değil, bu yüzden başka gerekçeler de arıyorum. Bence, bir şey null olamazsa ve bir veritabanı bir şeyin null olmadığını belirtmenize izin veriyorsa - sadece yapın. Özellikle değişiklik çok basitse.


1
Boş ve disk alanı ile ilgili dikkat edilmesi gereken noktalar için bu cevaba bakınız: stackoverflow.com/questions/5008753/… Kısacası, tablonuzda 8'den fazla sütun ve en az 1 boş değer sütunu varsa, tablonun tüm sütunlar için olduğundan daha fazla bayt gerekir null değil.
ypercubeᵀᴹ

1
@ ypercubeᵀᴹ: Kesin olarak, null bitmap yalnızca satırda gerçek bir null değer varsa eklenir : stackoverflow.com/a/7654497/939860 . Bu nedenle, NOT NULLkısıtlamaların depolama boyutu üzerinde doğrudan bir etkisi yoktur. Tabii ki, tüm sütunlar tanımlandığında NOT NULL, başlamak için boş bir bitmap olamaz. Öte yandan: gerçek değeri olmayan sütunlar için "boş" veya kukla değerler yerine NULL kullanırsanız, depolama boyutu genellikle çok daha küçüktür , çünkü boş bitmap nispeten daha küçüktür (nadir kenar durumları hariç).
Erwin Brandstetter

@ErwinBrandstetter o zaman kötülerim, o kısmı anlamamıştı. Boş değeri olmayan sütunlar için, bunları NULL veya NOT NULL olarak tanımlasanız da, depolamada gerçek bir fark yoktur, değil mi? İndeks depolama alanı için de aynı şey geçerli mi?
ypercubeᵀᴹ

5
"uygulama düzeyi null değerlerin burada görünmemesini sağlar" Hayır, görünmüyor. Bu belki bir uygulama boş değerlere ekleme değil emin olun. Ama psql (örneğin) var ve uygulamanız bilmeden kasıtlı ve yanlışlıkla null ekleyebilirsiniz.
Mike Sherrill 'Cat Recall'

5
Kimsenin tabloyu manuel olarak değiştirmediğinden emin olabilecek tek uygulama dbms'dir.
Mike Sherrill 'Cat Recall'

Yanıtlar:


9

Yeni bir programcı geldiğinde ve bu db'ye karşı bir uygulama yazmak zorunda kaldığında ne olur? Onlar bu alan x bilmiyorum sahiptir olmak NOT NULL.

Başka bir program, tüm x alanlarının NOT NULLsayım yapmak için olduğunu varsayabilir , ancak şimdi bazıları NULLyeni programdan kaynaklanıyor ve tutarsız ve izlenmesi zor hatalara yol açıyor.

IMHO, veri bütünlüğü kurallarını verilere olabildiğince yakın, yani veritabanında uygulamak her zaman en iyisidir. Bu şekilde, yeni uygulamalar ve / veya programcılar verilerinizi bozamaz.

Programcılar, uygulamalar, diller ve çerçeveler gelir ve gider. Veri ve veritabanları devam etme eğilimindedir. Veritabanı tutarsız, potansiyel olarak hatalı verilere karşı son savunma hattınızdır.

Make maksimum bile performans pahasına, veritabanınızın bütünlük kısıtlaması uygulama mekanizmalarının kullanılmasını. Doğru sonuçlar veren yavaş bir sistem, işleri yanlış yapan hızlı bir sistemden son derece üstündür!


1
IMHO it is always best to enforce data integrity rules as near to the data as possiblebu aslında hakkında yazdığım bağırsak hissiyle aynı. Ve tam da bu yüzden gerçek gerekçeler arıyorum. Kod incelemesi ve iyi dokümantasyonumuz var, bu nedenle yeni bir geliştiricinin bir şeyi bilmediğiyle ilgili endişeler değişikliği haklı çıkarmak için yeterli değil.
Salvador Dali

4
Kod incelemeleri ve iyi belgeler, (programlama veya diğer) hatalara karşı sizi garanti etmez.
ypercubeᵀᴹ

2
Ve kaç REAL PROGRAMMERSokuma tüm (hatta herhangi) onlar sıkı bir süre üzerinde konum bir prject içine sıkışmış almadan önce belgelerin?
Vérace

3
Bir keresinde veri ambarı için aynı tutuma sahip bir bankada inceleme yaptım. Onların durumunda - hiçbir referans bütünlüğü yok. Birisi belgeleri okuma ve arama tablolarındaki verileri silmediği için eski verilerin% 40'ı çöp oldu. Veri bütünlüğü ile kod incelemelerine ve belgelerine güvenmezsiniz - veritabanında açık hale getirirsiniz.
TomTom

5

Yorumlarda başkaları tarafından belirtildiği gibi NOT NULL, tablo spesifikasyonunuza eklemek , sorgularınızın performansını önemli ölçüde artırabilir (başka bir cevapta belirtilen çok iyi metodolojik nedenlere ek olarak).

Bunun nedeni, bir sütunun bir NULLdeğere sahip olamayacağını bilen sorgu optimize edicinin, NOT INvs. NOT EXISTSdurumunda olduğu gibi bu tür değerler için özel testleri hariç tutabilmesidir . Örneğin , belirli bir sorgu ile bir alan bildirilmemesinin (tablo her zaman boş olmayan değerler içerdiğinde)% 500 yürütme süresini artırdığı gösterilen bu blogu görebilirsiniz NOT NULL. Sonuç SQL Server için gösterilir, ancak benzer bir davranış sizinki gibi diğer ilişkisel DBMS'lerde de olabilir (veritabanınızın diğer sistemlere taşınabileceğinden bahsetmiyorum). Tahmin edebileceğiniz genel bir kural, sorgu optimize edici için daha fazla bilgi bulunduğunda daha verimli erişim planlarının üretilebileceğidir.


Teşekkür ederim. Aradığım cevap budur.
Salvador Dali

5
Hiçbir zaman NULL içermeyen sütunlar, NOT NULLbirden fazla nedenden dolayı tanımlanmalıdır , bununla ilgili herhangi bir tartışma yoktur. Ancak SQL Server ile ilgili blog bağlantısı Postgres için geçerli değildir ve bahsettiğiniz performans sonuçlarının hiçbirini kanıtlamaz. Hiç yok demiyorum, ama gerçek kanıtları görmek isterim .
Erwin Brandstetter

@ErwinBrandstetter, PostgreSQL optimizer hakkında çok yüksek beklentilerim vardı :( Birkaç testten sonra PostgreSQL'de blogda sunulan NOT IN sorgusunda NOT NULL kısıtlaması olan ve olmayan bir önemli fark bulamadım. ve size tamamen
Renzo

Hayır, silinmesi gerektiğini düşünmüyorum. Biri için 5 + oyu ve downvote yok.
ypercubeᵀᴹ

not inSıfırlanabilir sütunların semantiği farklı olsa da, bu ikisi arasında planda bazı farklar olmalı ?
Martin Smith

2

Uzay uygulamaları

Uzay etkileri @Erwin Brandstetter tarafından bu yazı içinde bahsettik edilir

Kısacası, eğer veritabanınız varsa totalColumns - 8, en yakın bayta (veya MAXALIGN) yuvarlanmış bir bit kaydedeceksiniz

  1. 8 sütundan fazla
  2. Tablodaki TÜM sütunlarNOT NULL

Performans sonuçları

Ancak, SEE tarafından @Erwin Brandstetter tarafından gönderilen bu yazıda ,

  1. "NOT NULL değerinin ayarının performans üzerinde hiçbir etkisi yoktur. Kontrol için önemsiz birkaç döngü."
  2. “... gerçekte kukla değerler yerine NULL'lar kullanarak. Veri türlerine bağlı olarak çok fazla disk alanı ve RAM kaydedebilir, böylece her şeyi hızlandırabilirsiniz.”

@Renzo'nun performans etkileri hakkında konuşan bir cevabı var - bunların hiçbirinin PostgreSQL için geçerli olduğunu varsaymam . PostgreSQL ile alakalı olduğunu kanıtlayan hiçbir şey bulamıyorum . Kaydedilen döngüler en temel sorguda bile ölçülemez.

CREATE TABLE foo (
  a int,
  b int NOT NULL,
  x float,
  y float NOT NULL
);

INSERT INTO foo ( a, b, x, y )
SELECT x, x, x, x
FROM generate_series(1,1E7) AS X(x);

EXPLAIN ANALYZE SELECT 1/a FROM foo;
EXPLAIN ANALYZE SELECT 1/b FROM foo;
EXPLAIN ANALYZE SELECT 1/x FROM foo;
EXPLAIN ANALYZE SELECT 1/y FROM foo;

Buna ek olarak, NULL dizinlerinin daha hızlı olup olmadığını görmek için bazı testler yaptım ve bunu doğrulayamadım. Bu inanılmaz faydalı konu Scott Marlowe tarafından 9.1'de sorgu planlayıcısı hakkında konuşan WHERE yan tümcelerinde kısmi dizin kullanabilmek için posta listelerinde bulabilirsiniz. Bunu aşağıdakileri çalıştırarak test ettim

CREATE TABLE foo ( a int );
CREATE TABLE bar ( a int NOT NULL );
INSERT INTO foo
  SELECT null FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT null FROM generate_series(1,1e5) AS x
;
INSERT INTO bar
  SELECT 0 FROM generate_series(1,1e5) AS x
  UNION ALL
  SELECT 10
  UNION ALL
  SELECT 0 FROM generate_series(1,1e5) AS x
;

Şimdi dizinleri yarattım,

CREATE INDEX foobar ON foo(a) WHERE a IS NOT NULL;
CREATE INDEX barbar ON bar(a) WHERE a <> 0;

Bu her iki durumda da planlayıcı, dizini seçerken endeksi kullanabildi ve = 10sırasıyla NULL veya 0 ararken seq tarama kullandı. Her iki kısmi indeks de aynı boyuttaydı. Ve tam dizinler (gösterilmemiştir) aynı boyuttaydı. Aynı metodolojiyi izleyerek tabloyu bir sıra 1..1e5ve bir boş / 0 değeri ve başka bir sıra ile yükledim 1..1e5. Her iki yöntem de tüm tabloyu kapsayan bir indeksle null / 0 bulabildi.

TLDR; özet

Planlayıcı yetersizliklerini dahil etmek için test etmeye değer olduğunu düşündüğüm performans endişelerinin çoğunda şu ya da bu şekilde hiçbir şeyi doğrulayamıyorum. Koçtan tasarruf etmek için null kullanmanın yararı gerçektir. Null kullanılmadan kaydedilen disk alanı göz ardı edilebilir ve bu, bir NULLABLEsütunu veya 8 sütundan az olan tablolarda abartılıdır . Bu gibi durumlarda disk alanı tasarrufu sağlanmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.