Postgres: SET kısıtlamasından SET NULL DEĞİL nasıl "daha verimli"


17

Gelen Sınırlamalar için PostgreSQL docs , diyor

Boş olmayan bir kısıtlama işlevsel olarak bir denetim kısıtlaması oluşturmaya eşdeğerdir CHECK (column_name IS NOT NULL), ancak PostgreSQL'de açık bir boş olmayan kısıtlama oluşturmak daha verimlidir.

merak ediyorum

  • "Daha verimli" ile tam olarak ne anlama geliyor?
  • Bunun CHECK (column_name IS NOT NULL)yerine kullanmanın zararları nelerdir SET NOT NULL?

Bir NOT VALID CHECKkısıtlama eklemek ve ayrı ayrı doğrulamak istiyorum (böylece AccessExclusiveLocksadece kısıtlama eklemek için kısa bir süre için ShareUpdateExclusiveLocktutulur ve daha sonra uzun doğrulama adımı için a tutulur):

ALTER TABLE table_name
  ADD CONSTRAINT column_constraint
  CHECK (column_name IS NOT NULL)
  NOT VALID;
ALTER TABLE table_name
  VALIDATE CONSTRAINT column_constraint;

Onun yerine:

ALTER TABLE table_name
  ALTER COLUMN column_name
  SET NOT NULL;


not inHer iki varyantla bir de yaparsanız, yürütme planları neye benziyor ? Aynı mı yoksa farklı mı?
Martin Smith

Yanıtlar:


12

Benim vahşi tahminim: "daha verimli", "kontrolü gerçekleştirmek için daha az zaman gerekli" anlamına gelir (zaman avantajı). Ayrıca "kontrolü gerçekleştirmek için daha az bellek gerekir" (alan avantajı) anlamına da gelebilir. Aynı zamanda "daha az yan etkisi vardır" anlamına da gelebilir (bir şeyi kilitlememek veya daha kısa süreler için kilitlemek gibi) ... ama bu "ekstra avantajı" bilmek veya kontrol etmek için bir yolum yok.

Olası bir alan avantajını kontrol etmenin kolay bir yolunu düşünemiyorum (sanırım, bugünlerde bellek ucuz olduğunda önemli değil). Öte yandan, olası zaman avantajını kontrol etmek o kadar da zor değil: sadece kısıtlama hariç, aynı olan iki tablo oluşturun. Yeterli sayıda satır ekleyin, birkaç kez tekrarlayın ve zamanlamaları kontrol edin.

Bu tablo ayarıdır:

CREATE TABLE t1
(
   id serial PRIMARY KEY, 
   value integer NOT NULL
) ;

CREATE TABLE t2
(
  id serial PRIMARY KEY,
  value integer
) ;

ALTER TABLE t2
  ADD CONSTRAINT explicit_check_not_null
  CHECK (value IS NOT NULL);

Bu, zamanlamaları saklamak için kullanılan ekstra bir tablodur:

CREATE TABLE timings
(
   test_number integer, 
   table_tested integer /* 1 or 2 */, 
   start_time timestamp without time zone,
   end_time timestamp without time zone,
   PRIMARY KEY(test_number, table_tested)
) ;

Ve bu, pgAdmin III ve pgScript özelliği kullanılarak yapılan testtir .

declare @trial_number;
set @trial_number = 0;

BEGIN TRANSACTION;
while @trial_number <= 100
begin
    -- TEST FOR TABLE t1
    -- Insert start time
    INSERT INTO timings(test_number, table_tested, start_time) 
    VALUES (@trial_number, 1, clock_timestamp());

    -- Do the trial
    INSERT INTO t1(value) 
    SELECT 1.0
      FROM generate_series(1, 200000) ;

    -- Insert end time
    UPDATE timings 
       SET end_time=clock_timestamp() 
     WHERE test_number=@trial_number and table_tested = 1;

    -- TEST FOR TABLE t2
    -- Insert start time
    INSERT INTO timings(test_number, table_tested, start_time) 
    VALUES (@trial_number, 2, clock_timestamp());

        -- Do the trial
    INSERT INTO t2(value) 
    SELECT 1.0
    FROM generate_series(1, 200000) ;

    -- Insert end time
    UPDATE timings 
       SET end_time=clock_timestamp() 
     WHERE test_number=@trial_number and table_tested = 2;

    -- Increase loop counter
    set @trial_number = @trial_number + 1;
end 
COMMIT TRANSACTION;

Sonuç aşağıdaki sorguda özetlenmiştir:

SELECT
    table_tested, 
    sum(delta_time), 
    avg(delta_time), 
    min(delta_time), 
    max(delta_time), 
    stddev_pop(delta_time) 
FROM
    (
    SELECT
        table_tested, extract(epoch from (end_time - start_time)) AS delta_time
    FROM
        timings
    ) AS delta_times
GROUP BY
    table_tested 
ORDER BY
    table_tested ;

Aşağıdaki sonuçlarla:

table_tested | sum     | min   | max   | avg   | stddev_pop
-------------+---------+-------+-------+-------+-----------
           1 | 176.740 | 1.592 | 2.280 | 1.767 | 0.08913
           2 | 177.548 | 1.593 | 2.289 | 1.775 | 0.09159

Değerlerin grafiği önemli bir değişkenlik gösterir:

Her 200000 satırlık ekleme için harcanan süre (saniye olarak)

Dolayısıyla, pratikte, CHECK (sütun NULL DEĞİLDİR) çok yavaştır (% 0,5). Bununla birlikte, bu küçük fark, zamanlamaların değişkenliğinin bundan daha büyük olması şartıyla herhangi bir rastgele nedenden kaynaklanabilir. Yani, istatistiksel olarak anlamlı değil.

Pratik bir bakış açısından, "daha verimli" yi görmezden NOT NULLgelirim, çünkü bunun gerçekten önemli olduğunu görmüyorum; Oysa an olmamasının AccessExclusiveLockbir avantaj olduğunu düşünüyorum .

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.