Postgres: SET NOT NULL เป็นอย่างไร "มีประสิทธิภาพมากขึ้น" กว่าข้อ จำกัด การตรวจสอบ


17

ในเอกสาร PostgreSQL สำหรับข้อ จำกัดกล่าวว่า

ข้อ จำกัด แบบไม่เป็นโมฆะเทียบเท่ากับการสร้างข้อ จำกัด การตรวจสอบCHECK (column_name IS NOT NULL)แต่ใน PostgreSQL การสร้างข้อ จำกัด แบบไม่เป็นโมฆะอย่างชัดเจนนั้นมีประสิทธิภาพมากกว่า

ฉันสงสัย

  • "มีประสิทธิภาพมากขึ้น" หมายความว่าอย่างไร
  • สิ่งที่เป็นอันตรายของการใช้งานCHECK (column_name IS NOT NULL)แทนSET NOT NULL?

ฉันต้องการเพิ่มNOT VALID CHECKข้อ จำกัด และตรวจสอบความถูกต้องแยกต่างหาก (ดังนั้นAccessExclusiveLockจะถูกเก็บไว้ในช่วงเวลาสั้น ๆ เท่านั้นสำหรับการเพิ่มข้อ จำกัด และจากนั้น a ShareUpdateExclusiveLockจะถูกเก็บไว้สำหรับขั้นตอนการตรวจสอบที่ยาวขึ้น):

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

แทน:

ALTER TABLE table_name
  ALTER COLUMN column_name
  SET NOT NULL;

1
ที่เกี่ยวข้อง: dba.stackexchange.com/questions/66840/ …
Erwin Brandstetter

แผนการดำเนินการมีลักษณะอย่างไรถ้าคุณทำnot inกับทั้งสองสายพันธุ์? พวกเขาเหมือนกันหรือแตกต่างกันอย่างไร
Martin Smith

คำตอบ:


12

ฉันเดาว่า: "มีประสิทธิภาพมากขึ้น" หมายถึง "ใช้เวลาน้อยลงในการตรวจสอบ" (ข้อได้เปรียบด้านเวลา) นอกจากนี้ยังอาจหมายถึง "จำเป็นต้องใช้หน่วยความจำน้อยกว่าเพื่อทำการตรวจสอบ" (ประโยชน์จากพื้นที่) มันอาจหมายถึง "มีผลข้างเคียงน้อยกว่า" (เช่นไม่ล็อคอะไรหรือล็อคมันเป็นระยะเวลาสั้น ๆ ) ... แต่ฉันไม่มีวิธีรู้หรือตรวจสอบว่า "ประโยชน์พิเศษ"

ฉันไม่สามารถคิดวิธีที่ง่ายในการตรวจสอบความได้เปรียบของพื้นที่ที่เป็นไปได้ (ซึ่งฉันเดาว่ามันไม่สำคัญเมื่อหน่วยความจำปัจจุบันราคาถูก) ในทางกลับกันก็ไม่ยากที่จะตรวจสอบความได้เปรียบด้านเวลาที่เป็นไปได้: เพียงสร้างสองตารางที่เหมือนกันโดยมีข้อยกเว้นเพียงข้อเดียวเท่านั้น แทรกจำนวนแถวที่มากพอทำซ้ำสองสามครั้งแล้วตรวจสอบเวลา

นี่คือการตั้งค่าตาราง:

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);

นี่เป็นตารางพิเศษที่ใช้สำหรับจัดเก็บเวลา:

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)
) ;

และนี่คือการทดสอบดำเนินการโดยใช้ pgAdmin III, และคุณลักษณะ pgScript

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;

ผลลัพธ์จะถูกสรุปในเคียวรีต่อไปนี้:

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 ;

ด้วยผลลัพธ์ต่อไปนี้:

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

กราฟของค่าแสดงความแปรปรวนที่สำคัญ:

เวลาที่ใช้ในการเพิ่มจำนวน 20,000 แถว (เป็นวินาที)

ดังนั้นในทางปฏิบัติการตรวจสอบ (คอลัมน์ไม่เป็นโมฆะ) จะช้ากว่าเล็กน้อยมาก (0.5%) อย่างไรก็ตามความแตกต่างเล็ก ๆ น้อย ๆ นี้อาจเป็นเพราะเหตุผลสุ่มใด ๆ โดยมีเงื่อนไขว่าความแปรปรวนของการกำหนดเวลามีขนาดใหญ่กว่านั้น ดังนั้นมันจึงไม่มีนัยสำคัญทางสถิติ

จากมุมมองที่ใช้งานได้จริงฉันจะเพิกเฉยต่อ "ประสิทธิภาพมากขึ้น" NOT NULLเพราะฉันไม่เห็นว่ามันมีความสำคัญ ในขณะที่ฉันคิดว่าไม่มีตัวตนAccessExclusiveLockเป็นข้อได้เปรียบ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.