อะไรคือผลของการไม่ระบุ NOT NULL ใน PostgreSQL สำหรับฟิลด์ที่ไม่สามารถเป็นโมฆะได้?


10

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

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

นอกจากนี้ยังname, num, timeไม่ได้ระบุไว้อย่างชัดเจนว่าNOT NULLในความเป็นจริงพวกเขาเป็นเพราะการบังคับใช้ที่เกิดขึ้นในด้านการประยุกต์ใช้


ความรู้สึกของฉันคือมันควรจะเปลี่ยน แต่ความแตกต่างคือระดับแอปพลิเคชันทำให้แน่ใจว่าค่า Null ไม่สามารถปรากฏที่นี่และไม่มีใครปรับเปลี่ยนตารางด้วยตนเอง

คำถามของฉันคืออะไรประโยชน์ (ประสิทธิภาพการจัดเก็บความสอดคล้องอย่างอื่น) และข้อเสีย (สมมติว่าฉันได้ตรวจสอบแล้วว่าไม่มีโมฆะในปัจจุบันและจากตรรกะทางธุรกิจควรไม่มีโมฆะ) โดยการตั้งค่าNOT NULLข้อ จำกัด ที่ชัดเจน?

เรามีขั้นตอนการตรวจสอบโค้ดที่ดีและมีเอกสารที่ดีพอสมควรดังนั้นความเป็นไปได้ที่คนใหม่บางคนจะส่งมอบสิ่งที่ทำลายข้อ จำกัด นี้ไม่เพียงพอที่จะพิสูจน์การเปลี่ยนแปลง

นี่ไม่ใช่การตัดสินใจของฉันดังนั้นนี่คือเหตุผลที่ฉันกำลังมองหาเหตุผลอื่น ๆ ในความคิดของฉันถ้าสิ่งที่ไม่สามารถเป็นโมฆะและฐานข้อมูลช่วยให้คุณระบุว่าสิ่งที่ไม่เป็นโมฆะ - เพียงแค่ทำมัน โดยเฉพาะอย่างยิ่งถ้าการเปลี่ยนแปลงนั้นง่ายมาก


1
ดูคำตอบนี้สำหรับข้อควรพิจารณาเกี่ยวกับ Nulls และพื้นที่ดิสก์: stackoverflow.com/questions/5008753/ …โดยย่อหากตารางของคุณมีมากกว่า 8 คอลัมน์และคอลัมน์ nullable อย่างน้อย 1 คอลัมน์ตารางจะต้องมีจำนวนไบต์ต่อแถวมากกว่าถ้าคอลัมน์ทั้งหมดเป็น กำหนดไม่เป็นโมฆะ
ypercubeᵀᴹ

1
@ ypercubeᵀᴹ: จะแม่นยำบิตแมป null จะถูกเพิ่มเพียงต่อแถวถ้ามีค่า Null ที่เกิดขึ้นจริงในแถว: stackoverflow.com/a/7654497/939860 ดังนั้นNOT NULLข้อ จำกัด ไม่มีผลกระทบโดยตรงกับขนาดของที่เก็บข้อมูล แน่นอนว่าเมื่อมีการกำหนดคอลัมน์ทั้งหมดNOT NULLจะไม่มีบิตแมปว่างเปล่าที่จะเริ่มต้นด้วย ในทางกลับกัน: ขนาดพื้นที่จัดเก็บโดยทั่วไปจะเล็กกว่ามากหากคุณใช้ค่า NULL แทนค่า "ว่าง" หรือดัมมี่สำหรับคอลัมน์ที่ไม่มีค่าจริงเนื่องจากบิตแมป null มีขนาดเล็กกว่ามาก (ยกเว้นกรณีขอบหายาก)
Erwin Brandstetter

@ErwinBrandstetter ฉันเสียแล้วไม่เข้าใจส่วนนั้น ดังนั้นสำหรับคอลัมน์ที่ไม่มีค่า Null ไม่มีความแตกต่างที่แท้จริงในการจัดเก็บไม่ว่าคุณจะกำหนดเป็น NULL หรือไม่ NULL ถูกต้องหรือไม่ นั่นเป็นพื้นที่สำหรับจัดเก็บดัชนีเหมือนกันหรือไม่
ypercubeᵀᴹ

5
"ระดับแอปพลิเคชันทำให้แน่ใจว่าค่า Null ไม่สามารถปรากฏที่นี่"ไม่ได้ มันอาจจะให้แน่ใจว่าโปรแกรมประยุกต์หนึ่งไม่ได้ใส่ nulls แต่ฉันมี psql (ตัวอย่าง) และฉันสามารถแทรกค่า Null ทั้งที่ตั้งใจและไม่ได้ตั้งใจโดยที่แอปพลิเคชันของคุณไม่ทราบ
Mike Catrill 'Cat Recall'

5
แอปพลิเคชันเดียวที่สามารถตรวจสอบให้แน่ใจว่าไม่มีใครแก้ไขตารางด้วยตนเองคือ dbms เอง
Mike Sherrill 'Cat Recall'

คำตอบ:


9

จะเกิดอะไรขึ้นเมื่อโปรแกรมเมอร์ใหม่มาถึงและต้องเขียนแอปกับฐานข้อมูลนั้น พวกเขาไม่ทราบว่าสนาม x มีNOT NULLจะเป็น

โปรแกรมอื่นอาจสันนิษฐานว่าทุกฟิลด์ x มีNOT NULLไว้สำหรับการนับจำนวนพูด แต่บางตอนก็เป็นNULLเพราะโปรแกรมใหม่ทำให้เกิดข้อผิดพลาดที่ไม่สอดคล้องกันและยากต่อการติดตาม

IMHO เป็นการดีที่สุดที่จะบังคับใช้กฎความสมบูรณ์ของข้อมูลใกล้กับข้อมูลมากที่สุดเช่นในฐานข้อมูล ด้วยวิธีนี้แอปใหม่และ / หรือโปรแกรมเมอร์ไม่สามารถทำให้ข้อมูลของคุณยุ่งเหยิงได้

โปรแกรมเมอร์แอปพลิเคชันภาษาและกรอบงานมาและไป ข้อมูลและฐานข้อมูลมีแนวโน้มที่จะคงอยู่ ฐานข้อมูลเป็นบรรทัดสุดท้ายของการป้องกันข้อมูลที่ไม่สอดคล้องและอาจผิดพลาด

ให้สูงสุดใช้ฐานข้อมูลของกลไกการบังคับใช้สมบูรณ์ จำกัด แม้ค่าใช้จ่ายของการทำงาน ระบบช้าที่ก่อให้เกิดผลลัพธ์ที่ถูกต้องคืออนันต์ดีกว่าหนึ่งอย่างรวดเร็วที่ได้รับสิ่งที่ไม่ถูกต้อง!


1
IMHO it is always best to enforce data integrity rules as near to the data as possibleที่จริงแล้วก็เหมือนกับความรู้สึกที่ฉันเขียน และนี่คือเหตุผลที่ฉันกำลังมองหาเหตุผลที่แท้จริง เรามีการตรวจสอบโค้ดในสถานที่และเอกสารที่ดีดังนั้นข้อกังวลเกี่ยวกับนักพัฒนาใหม่ที่ไม่รู้ว่ามีอะไรไม่พอที่จะพิสูจน์การเปลี่ยนแปลง
Salvador Dali

4
การตรวจสอบโค้ดและเอกสารที่ดีไม่ได้รับประกันว่าคุณจะได้รับข้อผิดพลาด (การเขียนโปรแกรมหรืออื่น ๆ )
ypercubeᵀᴹ

2
และเอกสารจำนวนเท่าใดที่REAL PROGRAMMERSอ่านทั้งหมด (หรือแม้แต่ใด ๆ ) ของเอกสารก่อนที่จะติดอยู่ในพื้นที่ที่พวกเขาอยู่ในกำหนดเส้นตาย?
Vérace

3
ฉันเคยตรวจสอบในธนาคารที่มีทัศนคติเดียวกันกับคลังข้อมูลของพวกเขา ในกรณีของพวกเขา - ไม่มีการอ้างอิงที่สมบูรณ์ ดีเกิดขึ้น 40% ของข้อมูลเก่าเป็นขยะเพราะมีคนไม่ได้อ่านเอกสารและลบข้อมูลในตารางการค้นหา คุณไม่เชื่อถือการตรวจสอบรหัสและเอกสารด้วยความสมบูรณ์ของข้อมูล - คุณทำให้มันชัดเจนในฐานข้อมูล
TomTom

5

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

เหตุผลก็คือเพิ่มประสิทธิภาพการค้นหาที่รู้ว่าคอลัมน์ไม่สามารถมีNULLค่าสามารถยกเว้นการทดสอบพิเศษสำหรับค่าดังกล่าวเช่นในNOT INเมื่อเทียบกับNOT EXISTSกรณีที่ คุณสามารถเห็นอินสแตนซ์ของบล็อกนี้ซึ่งจะแสดงให้เห็นว่าไม่ได้ประกาศเขตข้อมูลNOT NULL(เมื่อตารางมีค่าที่ไม่เป็นศูนย์เสมอ) ด้วยแบบสอบถามที่แน่นอนจะเพิ่มระยะเวลาดำเนินการ 500% ผลลัพธ์จะแสดงสำหรับ SQL Server แต่อาจมีพฤติกรรมที่คล้ายคลึงกันใน DBMS เชิงสัมพันธ์อื่น ๆ เช่นเดียวกับคุณ (ไม่ต้องพูดถึงความจริงที่ว่าฐานข้อมูลของคุณสามารถส่งไปยังระบบอื่นได้) กฎทั่วไปที่คุณสามารถสันนิษฐานได้คือเมื่อข้อมูลเพิ่มเติมพร้อมใช้งานกับเครื่องมือเพิ่มประสิทธิภาพคิวรีจึงสามารถสร้างแผนเข้าถึงที่มีประสิทธิภาพมากขึ้น


ขอบคุณ. นี่คือประเภทของคำตอบที่ฉันต้องการ
Salvador Dali

5
คอลัมน์ที่ไม่เคยมีค่า NULL ควรถูกกำหนดNOT NULLด้วยเหตุผลหลายประการไม่มีข้อโต้แย้งเกี่ยวกับเรื่องนั้น แต่การเชื่อมโยงไปยังบล็อกเกี่ยวกับ SQL Server นั้นไม่สามารถใช้ได้กับ Postgres และไม่ได้พิสูจน์ประสิทธิภาพที่คุณกล่าวถึง ไม่ได้บอกว่ามีไม่ใด ๆ แต่ผมชอบที่จะเห็นหลักฐานที่เกิดขึ้นจริง
Erwin Brandstetter

@ErwinBrandstetter ฉันมีความคาดหวังสูงมากเกี่ยวกับเครื่องมือเพิ่มประสิทธิภาพ PostgreSQL :( หลังจากการทดสอบหลายครั้งฉันไม่พบความแตกต่างอย่างมีนัยสำคัญในแบบสอบถาม NOT IN ที่นำเสนอในบล็อกใน PostgreSQL ด้วยและไม่มีข้อ จำกัด NULL ดังนั้นฉันจึงเปลี่ยนคำตอบ และฉันขอให้คุณถ้าคุณคิดว่าฉันควรลบมันทั้งหมด
Renzo

ไม่ฉันไม่คิดว่าควรจะลบ มันมี 5 คะแนนโหวตและไม่ลงคะแนนสำหรับหนึ่ง
ypercubeᵀᴹ

ความหมายของnot inคอลัมน์ nullable จะแตกต่างกันแม้ว่าจึงต้องมีบางอย่างที่แตกต่างกันในการวางแผนระหว่างสอง?
Martin Smith

2

ความหมายของอวกาศ

ความหมายของพื้นที่ถูกพูดถึงในโพสต์นี้โดย @Erwin Brandstetter

ในระยะสั้นคุณจะบันทึกหนึ่งtotalColumns - 8บิตที่ปัดเศษขึ้นเป็นไบต์ที่ใกล้ที่สุด (หรือMAXALIGN) หากฐานข้อมูลของคุณมี

  1. มากกว่า 8 คอลัมน์
  2. คอลัมน์ทั้งหมดในตารางคือNOT NULL

ความหมายของประสิทธิภาพ

อย่างไรก็ตามในโพสต์นี้บน SE โดย @Erwin Brandstetterเขากล่าว

  1. "การตั้งค่า NOT NULL ไม่มีผลกระทบต่อประสิทธิภาพการทำงานสองสามรอบสำหรับการตรวจสอบ - ไม่เกี่ยวข้อง"
  2. "... โดยการใช้ NULL แทนค่าดัมมี่ขึ้นอยู่กับชนิดข้อมูลคุณสามารถประหยัดเนื้อที่ดิสก์และ RAM ได้มากขึ้นดังนั้นจึงเร่ง .. ทุกอย่าง"

@Renzo มีคำตอบที่พูดคุยเกี่ยวกับผลกระทบต่อประสิทธิภาพการทำงาน - ฉันจะถือว่าไม่มีที่มีผลบังคับใช้กับ PostgreSQL ฉันไม่สามารถหาสิ่งที่พิสูจน์ใด ๆที่เป็นที่เกี่ยวข้องกับ PostgreSQL ไม่ว่าจะบันทึกรอบใดก็ตามไม่สามารถหาปริมาณได้แม้แต่ข้อความค้นหาที่เป็นพื้นฐานที่สุด

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;

นอกจากนี้ฉันได้ทำการทดสอบเพื่อดูว่าดัชนี NULL นั้นเร็วขึ้นหรือไม่และฉันไม่สามารถยืนยันได้ คุณสามารถค้นหาเธรดที่มีประโยชน์สุดขีดนี้โดย Scott Marloweในรายชื่อผู้รับจดหมายซึ่งพูดถึงผู้วางแผนแบบสอบถามใน 9.1 ความสามารถในการใช้ดัชนีบางส่วนในส่วนคำสั่ง WHERE ที่แตกต่างกัน ฉันทดสอบสิ่งนี้โดยใช้สิ่งต่อไปนี้

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
;

ตอนนี้ฉันสร้างดัชนี

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

ในทั้งสองกรณีนี้ผู้วางแผนสามารถใช้ดัชนีเมื่อเลือก= 10และใช้การสแกน seq เมื่อค้นหา NULL หรือ 0 ตามลำดับ ดัชนีบางส่วนทั้งสองมีขนาดเท่ากัน และดัชนีแบบเต็ม (ไม่แสดง) มีขนาดเท่ากัน ต่อไปนี้วิธีเดียวกับผมโหลดขึ้นตารางที่มีลำดับหนึ่ง1..1e5และเป็นคน null / 0 1..1e5ค่าและลำดับของผู้อื่น ทั้งสองวิธีสามารถหาค่า null / 0 พร้อมดัชนีที่ครอบคลุมทั้งตาราง

TLDR; สรุป

ฉันไม่สามารถยืนยันสิ่งใดสิ่งหนึ่งอย่างใดหรืออย่างอื่นในเรื่องการปฏิบัติงานส่วนใหญ่ที่ฉันคิดว่าเป็นการทดสอบที่คุ้มค่าสำหรับการรวมถึงการวางแผนที่ไม่เพียงพอ ประโยชน์ของการใช้ null เพื่อบันทึก ram เป็นจริง พื้นที่ดิสก์ที่บันทึกไว้โดยไม่ใช้ null นั้นมีขนาดเล็กมากและนั่นเป็นการกล่าวเกินจริงในตารางที่มีหนึ่งNULLABLEคอลัมน์หรือน้อยกว่า 8 คอลัมน์ ในกรณีดังกล่าวจะไม่มีการบันทึกพื้นที่ดิสก์

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