ทำไมเราไม่อนุญาตให้ NULL


125

ฉันจำได้ว่าอ่านบทความนี้เกี่ยวกับการออกแบบฐานข้อมูลและฉันยังจำได้ว่าคุณควรมีคุณสมบัติเขตข้อมูลของ NOT NULL ฉันจำไม่ได้ว่าทำไมถึงเป็นเช่นนั้น

สิ่งที่ฉันคิดได้ก็คือในฐานะนักพัฒนาแอปพลิเคชันคุณไม่ต้องทดสอบค่า NULL และค่าข้อมูลที่ไม่มีอยู่ (ตัวอย่างเช่นสตริงว่างสำหรับสตริง)

แต่คุณจะทำอย่างไรในกรณีของวันที่วันที่และเวลา (SQL Server 2008) คุณต้องใช้วันที่ในประวัติศาสตร์หรือจุดต่ำสุด

ความคิดใด ๆ เกี่ยวกับเรื่องนี้?


4
คำตอบนี้มีข้อมูลเชิงลึกเกี่ยวกับการใช้งาน NULL dba.stackexchange.com/questions/5176/…
Derek Downey

10
จริงๆ? ทำไม RDBMS อนุญาตให้เราใช้ค่า NULL เลยถ้าเราไม่ควรใช้มัน ไม่มีอะไรผิดปกติกับ NULL ตราบใดที่คุณรู้วิธีจัดการกับพวกเขา
Fr0zenFyr

3
นี่คือการสร้างแบบจำลองข้อมูล BI หรือไม่ โดยทั่วไปแล้วคุณไม่ควรอนุญาตให้ใช้ค่า null ในตารางข้อเท็จจริง ... มิฉะนั้นค่า null จะเป็นเพื่อนของคุณเมื่อใช้อย่างถูกต้อง =)
sam yi

2
@ Fr0zenFyr เพียงเพราะ RDBMS อนุญาตให้เราทำบางสิ่งบางอย่างมันไม่จำเป็นต้องเป็นความคิดที่ดี ไม่มีอะไรบังคับให้เราประกาศคีย์หลักหรือคีย์เฉพาะในตาราง แต่มีข้อยกเว้นเล็กน้อยที่เราทำ แต่อย่างใด
Lennart

3
ฉันคิดว่าการรักษาที่สมบูรณ์ในเรื่องนี้จะต้องอ้างอิงถึงข้อกำหนดดั้งเดิมของ Codd ที่ RDBMS ต้องมีวิธีที่เป็นระบบในการจัดการกับข้อมูลที่หายไป ในโลกแห่งความเป็นจริงมีสถานการณ์ที่ตำแหน่งของข้อมูลถูกสร้างขึ้น แต่ไม่มีข้อมูลที่จะใส่เข้าไป Data Architect ต้องมีการตอบสนองต่อสิ่งนี้ไม่ว่าจะเกี่ยวข้องกับการออกแบบฐานข้อมูลการเขียนโปรแกรมประยุกต์หรือทั้งสองอย่าง ค่า NULL ของ SQL นั้นน้อยกว่าความสมบูรณ์แบบในการตอบสนองความต้องการนี้ แต่ก็ยังดีกว่าไม่มีอะไรเลย
Walter Mitty

คำตอบ:


230

ฉันคิดว่าคำถามนั้นเป็นถ้อยคำที่ไม่ดีพอเนื่องจากถ้อยคำบอกเป็นนัยว่าคุณได้ตัดสินใจว่า NULLs นั้นไม่ดี บางทีคุณอาจหมายถึง "เราควรอนุญาตให้ NULLs"

อย่างไรก็ตามนี่คือสิ่งที่ฉันทำได้: ฉันคิดว่า NULL เป็นสิ่งที่ดี เมื่อคุณเริ่มป้องกัน NULL เพียงเพราะ "NULL ไม่ดี" หรือ "NULLs ยาก" คุณจะเริ่มสร้างข้อมูล ตัวอย่างเช่นถ้าคุณไม่ทราบวันเกิดของฉัน คุณจะใส่อะไรลงในคอลัมน์จนกว่าคุณจะรู้ หากคุณเป็นคนที่ชอบ anti-NULL มากมายคุณจะเข้าสู่ 1900-01-01 ตอนนี้ฉันจะถูกวางไว้ในแผนกผู้สูงอายุและอาจได้รับโทรศัพท์จากสถานีข่าวท้องถิ่นของฉันแสดงความยินดีกับชีวิตที่ยาวนานของฉันถามความลับของฉันที่จะมีชีวิตที่ยาวนาน ฯลฯ

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

มีความสมดุล แต่ - ไม่ใช่ทุกคอลัมน์ในตัวแบบข้อมูลของคุณที่ควรจะเป็นโมฆะ มักจะมีฟิลด์ตัวเลือกในแบบฟอร์มหรือชิ้นส่วนของข้อมูลที่ไม่ได้รับการรวบรวมในเวลาที่แถวถูกสร้างขึ้น แต่นั่นไม่ได้หมายความว่าคุณสามารถเลื่อนประชากรทั้งหมดของข้อมูล :-)

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

อย่ากลัว NULL แต่จงยินดีที่จะเรียนรู้หรือกำหนดเวลาและสถานที่ที่ควรใช้และเมื่อใดและที่ไหนที่ไม่ควรใช้


3
"บางค่าโทเค็นโดยพลการเพื่อเป็นตัวแทนของความจริงที่ว่ามันไม่เป็นที่รู้จัก" นี้เป็นที่รู้จักกันเป็นค่าแมวมอง
อเล็กซานเด

4
แต่อะไรทำให้คุณไม่สามารถสร้างตารางแยกbirth_dateที่คุณเก็บวันเกิด birth_dateถ้าวันเกิดเป็นที่รู้จักแล้วก็อย่าใส่วันเดือนปีเกิดลงใน Nulls เป็นหายนะ
Eldar Agalarov

6
@EldarAgalarov นั่นดูเหมือนเหตุผลทรัมป์ ("หายนะ" ทำไมเหรอ? สำหรับใคร? ความคิดเห็นของคุณที่มีบางอย่างเกี่ยวกับ "ภัยพิบัติ" ไม่ได้ทำให้เป็นเช่นนั้น) อย่างไรก็ตามวันเกิดเป็นเพียงตัวอย่างหนึ่งเท่านั้น หากคุณมีบุคลากรหรือสมาชิกหรือลูกค้าที่มี 15 คอลัมน์ที่อาจเป็นโมฆะคุณจะสร้างตารางรอง 15 ตารางหรือไม่ ถ้าคุณมี 50 เกิดอะไรขึ้นถ้าตารางข้อเท็จจริงของ DW มี 500 การบำรุงรักษาเพื่อป้องกันไม่ให้ NULL ที่น่ากลัวขนาดใหญ่ออกจากฐานข้อมูลของคุณกลายเป็นเลวร้าย 10 เท่าเช่น "ภัยพิบัติ" ใด ๆ ที่คุณกลัว ...
Aaron Bertrand

3
@AaronBertrand หากตารางของคุณมี 15 คอลัมน์ที่อาจเป็นโมฆะมันมีกลิ่นไม่ดีจริง ๆ ^^ ไม่ใช่ว่ามีคอลัมน์จำนวนมากที่ไม่ดีโดยเนื้อแท้ แต่มันอาจบ่งบอกถึงการออกแบบที่ไม่ดี แต่มันจะตั้งคำถาม
โปรแกรม

2
@Wildcard คุณไม่เคยเห็นคนเก็บไว้1900-01-01เพื่อหลีกเลี่ยงค่า NULL วันที่ / เวลา? โอเคถ้าอย่างนั้น. นอกจากนี้ NULL = unknown และ unknown = false ฉันไม่แน่ใจว่าปัญหานี้อาจทำให้คนอื่นไม่ได้เกิดมารู้ว่า (เช่นพวกเขาไม่ได้เกิดมารู้สิ่งต่าง ๆ มากมายใน RDBMS ที่ซับซ้อน) อีกครั้งโบกมือแล้วพูดว่า "ปัญหา! ภัยพิบัติ!" ไม่ได้ทำอย่างนั้น
Aaron Bertrand

57

เหตุผลที่ก่อตั้งขึ้นคือ:

  • NULL ไม่ใช่ค่าและดังนั้นจึงไม่มีประเภทข้อมูลที่แท้จริง Nulls ต้องการการจัดการเป็นพิเศษทั่วทุกแห่งเมื่อรหัสที่อาศัยประเภทจริงอาจได้รับ NULL ที่ไม่ได้พิมพ์

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

  • ความหมายของการเป็นโมฆะเฉพาะเจาะจงใด ๆ เหลืออยู่เพื่อการประยุกต์ใช้ซึ่งแตกต่างจากค่าที่แท้จริง

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

  • พวกเขาไม่จำเป็นต้องมีฐานข้อมูลเชิงสัมพันธ์เป็นที่ถกเถียงกันอยู่ใน“วิธีการจัดการข้อมูลที่ขาดหายไปโดยไม่ต้อง Nulls” การทำให้เป็นมาตรฐานต่อไปคือขั้นตอนแรกที่ชัดเจนในการลองใช้ตาราง NULL

นี่ไม่ได้หมายความว่าไม่ควรอนุญาตให้ NULL มันไม่เถียงว่ามีเหตุผลที่ดีมากที่จะไม่อนุญาตให้โมฆะใดก็ตามที่เป็นไปได้

อย่างมีนัยสำคัญมันโต้แย้งว่าพยายามอย่างหนัก - ผ่านการออกแบบสคีมาที่ดีขึ้นและเอ็นจิ้นฐานข้อมูลที่ดีขึ้นและภาษาฐานข้อมูลที่ดีขึ้น - เพื่อให้สามารถหลีกเลี่ยง NULL ได้บ่อยขึ้น

Fabian Pascal ตอบสนองต่อจำนวนของการขัดแย้งใน“Nulls โมฆะ”


3
ลิงก์ของคุณไปยัง "วิธีจัดการกับข้อมูลที่หายไปโดยไม่มี Nulls" แสดงให้เห็นอย่างชัดเจนว่าทำไมเราถึงทำไม่ได้หากไม่มีโมฆะ: คำแนะนำหลายข้ออาจเป็นไปไม่ได้ที่จะนำไปใช้อย่างสมเหตุสมผลบน RDBMS หลัก ๆ
Jack Douglas

7
แจ็ค: ใช่ แต่“ การใช้งานในปัจจุบันไม่สามารถทำได้” ไม่ใช่ข้อโต้แย้งสำหรับสถานะเดิม :-)
bignose

17
การพูดแบบนั้นเป็นการบอกว่าเราไม่ควรบินเพราะเครื่องบินไม่สมบูรณ์แบบ?
Aaron Bertrand

11
ไม่ได้มีการกล่าวว่าผู้ขายควรหยุดอ้างข้อแก้ตัวสำหรับโมฆะที่อาจถูกต้องเป็นเวลาสี่สิบปีที่แล้ว แต่มีอายุการใช้งานที่ยาวนานกว่า เวลา I / O ไม่อยู่ในลำดับความสำคัญ 80ms อีกต่อไป รอบ CPU เดี่ยวจะไม่อยู่ในลำดับของขนาดของไมโครวินาทีอีกต่อไป ขีด จำกัด หน่วยความจำไม่อยู่ในลำดับความสำคัญของ Megs สองสาม ซึ่งแตกต่างจากสี่สิบปีที่ผ่านมาความเร็วและความสามารถของฮาร์ดแวร์ที่จำเป็นสำหรับการทำงานโดยไม่มีค่าใช้จ่ายตอนนี้มีอยู่ด้วยค่าใช้จ่ายที่ไม่ต้องห้าม เขากำลังพูดว่าถึงเวลาแล้วที่จะเดินหน้าต่อ
Erwin Smout

2
ลิงก์ "NULL Confusion" ลิงก์ตาย
jpmc26

32

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

IIRC, Codd แนะนำการใช้งานปัจจุบันของโมฆะ (ความหมายไม่ปัจจุบัน / หายไป) สามารถปรับปรุงได้โดยมีสองตัวทำเครื่องหมายโมฆะมากกว่าหนึ่ง "ไม่ปัจจุบัน แต่ใช้งานได้" และ "ไม่อยู่และไม่สามารถใช้งานได้" ไม่สามารถจินตนาการได้ว่าการออกแบบเชิงสัมพันธ์จะได้รับการปรับปรุงโดยบุคคลนี้ได้อย่างไร


2
ฉันขอแนะนำให้มีชุดที่ผู้ใช้กำหนดแตกต่างกันnullและตรรกะที่ผู้ใช้กำหนดเองหลายค่าที่จะไปกับพวกเขา: p
Jack Douglas

13
นั่นไม่ใช่ตัวเลือกเดียว คุณไม่รวมตัวเลือกการทำให้เป็นมาตรฐาน: แทนคอลัมน์ที่อาจมีหรือไม่มีค่าให้ใช้ตารางอื่นซึ่งอาจหรืออาจไม่มีแถวที่เกี่ยวข้องสำหรับตารางแรก ความหมายของการมีหรือไม่มีของแถวถูกยกให้อยู่ในความหมายของตารางและไม่มีพิเศษปลอกโมฆะหรือแมวมองค่า ฯลฯ
bignose

7
การมีอยู่ของ NULL ไม่จำเป็นต้องมีค่าปลอกพิเศษหรือค่า Sentinel นี่เป็นเพียงอาการของคนบางคนตัดสินใจจัดการกับ NULLs
Aaron Bertrand

เป็นที่น่าสังเกตว่า '' นั้นแตกต่างจาก null บน PostgreSQL (ไม่ใช่ Oracle) และให้เครื่องหมายมาร์กเกอร์แบบสองเท่าและคุณสามารถใช้ 0 สำหรับคอลัมน์ตัวเลขได้ ปัญหาที่เกิดขึ้นกับ 0 คือมันไม่ได้ผลกับกุญแจต่างประเทศ
Chris Travers

13

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

  1. ค่า Null ทำให้การพัฒนายากขึ้นและมีแนวโน้มที่จะเกิดข้อบกพร่อง
  2. ค่า Null สร้างคิวรี, โพรซีเดอร์ที่จัดเก็บและดูความซับซ้อนและข้อบกพร่องได้ง่ายขึ้น
  3. ค่า Null ใช้พื้นที่ (? ไบต์ขึ้นอยู่กับความยาวคอลัมน์คงที่หรือ 2 ไบต์สำหรับความยาวคอลัมน์แปรผัน)
  4. ค่า Null สามารถและมักจะส่งผลกระทบต่อการจัดทำดัชนีและคณิตศาสตร์

ฉันใช้เวลานานมากในการตอบสนองความคิดเห็นบทความและคำแนะนำทั่วอินเทอร์เน็ต จำเป็นต้องพูดข้อมูลส่วนใหญ่เกี่ยวกับการตอบสนองของ @ AaronBertrand นี่คือเหตุผลที่ฉันรู้สึกว่าจำเป็นต้องตอบคำถามนี้

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

ที่ถูกกล่าวว่าตารางพนักงานเดียวกันมักจะเก็บข้อมูลการตรวจสอบบางประเภท เป็นเรื่องปกติในสภาพแวดล้อมขององค์กรที่พนักงานจะแสดงรายการในฐานข้อมูลสำหรับทรัพยากรบุคคลและการบัญชี แต่ไม่จำเป็นต้องมีหรือต้องการรายละเอียดการรับรองความถูกต้องเสมอไป คำตอบส่วนใหญ่จะนำคุณไปสู่การเชื่อว่าการลบเขตข้อมูลเหล่านั้นเป็นโมฆะหรือในบางกรณีสร้างบัญชีสำหรับพวกเขา แต่ไม่ส่งข้อมูลประจำตัวให้พวกเขา อดีตจะทำให้ทีมพัฒนาของคุณเขียนโค้ดเพื่อตรวจสอบค่า NULL และจัดการกับพวกเขาตามลำดับและหลังจะมีความเสี่ยงด้านความปลอดภัยมาก! บัญชีที่ยังไม่เคยใช้ในระบบจะเพิ่มจำนวนจุดเชื่อมต่อที่เป็นไปได้สำหรับแฮ็กเกอร์เท่านั้นและจะใช้พื้นที่ฐานข้อมูลที่มีค่าสำหรับบางสิ่งที่ไม่เคยใช้

จากข้อมูลข้างต้นวิธีที่ดีที่สุดในการจัดการกับข้อมูลที่เป็นโมฆะที่ WILL จะใช้คืออนุญาตให้มีค่า Nullable มันเศร้า แต่จริงและนักพัฒนาของคุณจะเกลียดคุณ ข้อมูลประเภท nullable ประเภทที่สองควรใส่ไว้ในตารางที่เกี่ยวข้อง (IE: Account, Credentials และอื่น ๆ ) และมีความสัมพันธ์แบบหนึ่งต่อหนึ่ง สิ่งนี้อนุญาตให้ผู้ใช้มีอยู่โดยไม่มีหนังสือรับรองยกเว้นจำเป็นต้องมี สิ่งนี้จะลบความเสี่ยงด้านความปลอดภัยพิเศษพื้นที่ฐานข้อมูลที่มีค่าและจัดให้มีฐานข้อมูลที่สะอาดขึ้นมาก

ด้านล่างเป็นโครงสร้างตารางแบบง่ายมากที่แสดงทั้งคอลัมน์ nullable ที่จำเป็นและความสัมพันธ์แบบหนึ่งต่อหนึ่ง

ไม่รู้จัก Nullable และความสัมพันธ์แบบหนึ่งต่อหนึ่ง

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


2
ฉันเพิ่งจะเปลี่ยนเพื่อที่จะไม่มีTerminationDateในบันทึกของพนักงาน แต่มีตารางTerminatedEmployeeที่พนักงานถูกย้ายไปที่ (ไม่คัดลอก) โดยแอปพลิเคชันเมื่อพวกเขาถูกยกเลิก เห็นได้ชัดว่าใช้งานได้ดีกับตารางบัญชีเพราะจะไม่มีบัญชีที่เชื่อมโยงอยู่ในTerminatedEmployeeตาราง หากคุณยังต้องการหมายเลขโทรศัพท์ฉันจะย้อนกลับคีย์ต่างประเทศเพื่อให้พนักงานและตารางพนักงานที่ถูกยกเลิกมีรหัสของหมายเลขโทรศัพท์แทนวิธีอื่น
Programster

2
แท้จริงฉันสามารถไปหลายวันเกี่ยวกับสาเหตุที่จะไม่ดี ตารางที่ซ้ำซ้อน, แนวทางปฏิบัติ SQL ที่ไม่ดี, ทำให้ผู้พัฒนาของคุณต้องค้นหาข้อมูลพนักงานสองเรื่อง, ปัญหาเกี่ยวกับการรายงาน, ปัญหาเกี่ยวกับ URIs โดยตรงกับพนักงานที่ไม่มีอยู่ (ถูกย้ายแล้ว) และรายการดำเนินต่อไป และบน มันเป็นเรื่องปกติที่จะมี NULLS สำหรับฟิลด์ที่สักวันหนึ่งจะมีค่ามันเป็นอีกเรื่องที่มีฟิลด์ที่ไม่เคยเติมและไม่เคยใช้ จำนวนของปัญหาที่อาจเกิดขึ้นและวิธีแก้ไขปัญหาเพื่อให้งานนี้จะไม่คุ้มค่ากับปัญหาเล็ก ๆ ของการตรวจสอบ NULL บนเขตข้อมูล
Nicholas Aguirre

1
ฉันไม่เห็นด้วย. สิ่งเดียวที่ซ้ำซ้อนคือฟิลด์ว่างสำหรับวันที่สิ้นสุดซึ่งอาจไม่สมบูรณ์ นักพัฒนาจะต้องดูในตารางที่เหมาะสมสำหรับข้อมูลที่ต้องการและสามารถปรับปรุงประสิทธิภาพได้ ถ้าด้วยเหตุผลบางอย่างคุณต้องการพนักงานที่ถูกเลิกจ้างและไม่สิ้นสุดซึ่งได้รับการแก้ไขโดยการเข้าร่วม แต่ 90% ของเวลาที่แอปพลิเคชันของคุณอาจต้องการอย่างใดอย่างหนึ่ง ฉันคิดว่าเลย์เอาต์ที่ฉันระบุนั้นดีกว่าเพราะเป็นไปไม่ได้ที่จะมีวันที่สิ้นสุดในพนักงานและสำหรับเขาที่จะยังมีบัญชีอยู่
โปรแกรม

2
ฉันไม่ได้พูดข้อมูลที่ซ้ำซ้อนฉันพูดถึงตารางที่ซ้ำซ้อน นอกจากนี้การเปลี่ยนแปลงใด ๆ ในตารางพนักงานจะต้องไหลลงสู่ตารางที่ถูกยกเลิก สิ่งนี้ทำให้เกิดข้อผิดพลาดของแอพและทำให้งานของผู้พัฒนานั้นยากขึ้นมาก นอกจากนี้ฟิลด์วันที่สิ้นสุดจะถูกเติมเต็มสำหรับเกือบทุกคน มันสิ้นเปลืองและมีปัญหาในการสร้างโครงสร้างตารางที่สองเหมือนกันและย้ายข้อมูลไปรอบ ๆ ไม่รวมการทดสอบในแต่ละครั้งเพื่อให้แน่ใจว่าข้อมูลตารางถูกย้ายและทำความสะอาด เป็นวิธีปฏิบัติที่ไม่ดีในการลบข้อมูลออกจากตารางแม้ว่าจะเป็นการย้ายเท่านั้น หากคุณกังวลเกี่ยวกับเขตข้อมูลเดียวที่ ...
Nicholas Aguirre

1
... ที่เกือบจะเต็มเวลาแล้วสร้างตารางที่สิ้นสุดด้วยความสัมพันธ์ 1to1 กลับไปที่พนักงาน ฉันทำงานกับฐานข้อมูลที่หลากหลายตลอดทั้งวันในฐานะ DBA และในฐานะนักพัฒนาและฉันดีใจที่ฉันยังไม่ได้เจอกับโครงสร้างที่คุณเสนอ โดยเฉพาะอย่างยิ่งจากมุมมองของนักพัฒนามันเป็นฝันร้ายที่จะเขียนและตรวจสอบข้อผิดพลาดทุกอย่างเพราะคุณไม่รู้ว่ามันมาจากไหน แม้แต่การเขียนการเข้าร่วมข้อมูลที่ส่งคืนไปยังซอฟต์แวร์จะมีเขตข้อมูลที่มีข้อมูล null ซึ่งยังต้องการให้คุณทำการทดสอบเช่นกัน
Nicholas Aguirre

13

นอกเหนือจากปัญหาทั้งหมดที่นักพัฒนา NULL สร้างความสับสนแล้ว NULL ยังมีข้อเสียเปรียบที่ร้ายแรงอีกประการหนึ่งคือประสิทธิภาพ

คอลัมน์ NULL'able เป็นความเสียหายจากมุมมองประสิทธิภาพ พิจารณาเลขคณิตเลขจำนวนเต็มเป็นตัวอย่าง ในโลกที่ไม่มีสติ NULL มันเป็น "ง่าย" ในการคำนวณเลขจำนวนเต็ม vectorise ในฐานข้อมูลรหัสเครื่องยนต์โดยใช้คำสั่ง SIMD เพื่อทำการคำนวณใด ๆ ที่ความเร็วเร็วกว่า 1 แถวต่อรอบ CPU อย่างไรก็ตามในขณะที่คุณแนะนำ NULL คุณต้องจัดการกับกรณีพิเศษทั้งหมดที่ NULL สร้างขึ้น ชุดคำสั่ง CPU สมัยใหม่ (อ่าน: ตรรกะ x86 / x64 / ARM และ GPU ด้วย) ไม่ได้ติดตั้งเพื่อให้ทำสิ่งนี้ได้อย่างมีประสิทธิภาพ

พิจารณาแบ่งเป็นตัวอย่าง ในระดับที่สูงมากนี่คือตรรกะที่คุณต้องการด้วยจำนวนเต็มที่ไม่ใช่ค่าว่าง:

if (b == 0)
  do something when dividing by error
else
  return a / b

ด้วย NULL สิ่งนี้จะกลายเป็นเรื่องยุ่งยากอีกเล็กน้อย ร่วมกับbคุณจะต้องเป็นตัวบ่งชี้ถ้าเป็นโมฆะและในทำนองเดียวกันสำหรับb aการตรวจสอบตอนนี้กลายเป็น:

if (b_null_bit == NULL)
   return NULL
else if (b == 0) 
   do something when dividing by error
else if (a_null_bit == NULL)
   return NULL
else 
   return a / b

เลขคณิต NULL ช้าลงอย่างมากที่จะทำงานบน CPU ที่ทันสมัยกว่าเลขคณิตไม่เป็นโมฆะ (โดยประมาณ 2-3 เท่า)

มันจะแย่ลงเมื่อคุณแนะนำ SIMD ด้วย SIMD ซีพียู Intel ที่ทันสมัยสามารถทำการแบ่งจำนวนเต็ม 4 x 32 บิตในการเรียนการสอนเดียวเช่นนี้

x_vector = a_vector / b_vector
if (fetestexception(FE_DIVBYZERO))
   do something when dividing by zero
return x_vector;

ตอนนี้มีวิธีจัดการกับ NULL ในที่ดิน SIMD ด้วย แต่สิ่งนี้ต้องการการใช้เวกเตอร์และการลงทะเบียน CPU เพิ่มเติมและทำการปิดบังบิตที่ชาญฉลาด ถึงแม้จะมีลูกเล่นที่ดี แต่ประสิทธิภาพของการคำนวณเลขจำนวนเต็ม NULL จะเพิ่มขึ้นในช่วงที่ช้าลง 5-10 เท่าสำหรับการแสดงออกที่ค่อนข้างเรียบง่าย

บางสิ่งบางอย่างเช่นข้างต้นมีไว้สำหรับมวลรวมและบางส่วนสำหรับการรวมเช่นกัน

กล่าวอีกนัยหนึ่ง: การดำรงอยู่ของ NULL ใน SQL เป็นความต้านทานที่ไม่ตรงกันระหว่างทฤษฎีฐานข้อมูลและการออกแบบที่แท้จริงของคอมพิวเตอร์สมัยใหม่ มีเหตุผลที่ดีที่ NULL สร้างความสับสนให้กับนักพัฒนาเพราะจำนวนเต็มไม่สามารถเป็น NULL ในภาษาการเขียนโปรแกรมที่มีเหตุผลส่วนใหญ่นั่นไม่ใช่วิธีการทำงานของคอมพิวเตอร์


10

คำถามที่น่าสนใจ

สิ่งที่ฉันคิดได้ก็คือในฐานะนักพัฒนาแอปพลิเคชันคุณไม่ต้องทดสอบค่า NULL และค่าข้อมูลที่ไม่มีอยู่ (ตัวอย่างเช่นสตริงว่างสำหรับสตริง)

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

แต่คุณจะทำอย่างไรในกรณีของวันที่วันที่และเวลา (SQL Server 2008) คุณต้องใช้วันที่ในประวัติศาสตร์หรือจุดต่ำสุด

นั่นแสดงให้เห็นถึงปัญหาที่มีค่า Null ทันทีนั่นคือค่าที่เก็บไว้ในตารางอาจหมายถึง "ค่านี้ไม่ได้ใช้" หรือ "เราไม่รู้" ด้วยสตริงสตริงว่างสามารถทำหน้าที่เป็น "สิ่งนี้ไม่ได้ใช้" แต่มีวันที่และเวลาไม่มีการประชุมดังกล่าวเพราะไม่มีค่าที่ถูกต้องซึ่งโดยทั่วไปหมายถึงสิ่งนี้ โดยทั่วไปแล้วคุณจะติดอยู่โดยใช้ NULL

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

แก้ไข: หนึ่งพื้นที่ที่มีค่า NULL ที่ขาดไม่ได้อยู่ในคีย์ต่างประเทศ ที่นี่พวกเขามักจะมีเพียงหนึ่งความหมายเหมือนกับโมฆะในความหมายภายนอกเข้าร่วม นี่เป็นข้อยกเว้นของปัญหาแน่นอน


10

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

เพียงระวังว่า RDBMS ของคุณจัดการกับพวกเขาในการดำเนินการ SELECT เช่นคณิตศาสตร์และในดัชนีได้อย่างไร


-12

ว้าวคำตอบที่ถูกต้อง "ไม่อนุญาตให้มีค่า NULL เมื่อคุณไม่ต้องทำเพราะประสิทธิภาพในการทำงานลดลง" เป็นคำตอบสุดท้าย ฉันจะโหวตมันแล้วทำอย่างละเอียด เมื่อ RDBMS อนุญาตให้ NULLs สำหรับคอลัมน์ที่ไม่กระจัดกระจายคอลัมน์นั้นจะถูกเพิ่มลงในบิตแมปที่ติดตามว่าค่านั้นเป็น NULL สำหรับแต่ละแถวหรือไม่ ดังนั้นโดยการเพิ่มความสามารถของ NULL ให้กับคอลัมน์ในตารางที่คอลัมน์ทั้งหมดไม่อนุญาตให้ NULL คุณกำลังเพิ่มพื้นที่เก็บข้อมูลที่จำเป็นสำหรับการบันทึกตาราง นอกจากนี้คุณต้องการให้ RDBMS อ่านและเขียนลงในบิตแมปลดประสิทธิภาพในการดำเนินการทั้งหมด

นอกจากนี้ในหลาย ๆ กรณีการอนุญาตให้ NULLs แบ่งเป็น 3NF ในขณะที่ฉันไม่ใช่ stickler สำหรับ 3NF เหมือนเพื่อนร่วมงานหลายคนของฉันให้พิจารณาสถานการณ์สมมติต่อไปนี้:

ในตารางบุคคลมีคอลัมน์เรียกว่า DateOfDeath ซึ่งเป็นโมฆะ หากบุคคลนั้นเสียชีวิตมันจะถูกเติมด้วย DateOfDeath ของพวกเขามิฉะนั้นจะถูกปล่อยให้เป็น NULL นอกจากนี้ยังมีคอลัมน์บิตที่ไม่เป็นโมฆะเรียกว่า IsAlive คอลัมน์นี้ถูกตั้งค่าเป็น 1 ถ้าบุคคลนั้นยังมีชีวิตอยู่และ 0 ถ้าบุคคลนั้นตาย กระบวนงานที่เก็บไว้ส่วนใหญ่ใช้คอลัมน์ IsAlive พวกเขาจะดูแลเฉพาะในกรณีที่บุคคลนั้นยังมีชีวิตอยู่ไม่ใช่ DateOfDeath ของพวกเขา

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

สคริปต์ T-SQL ที่มีประโยชน์สำหรับการค้นหาคอลัมน์ที่ไม่มีค่าได้โดยไม่มี NULL ในสกีมาทั้งหมดคือ:

select 'IF NOT EXISTS (SELECT 1 FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ' WHERE ' + QUOTENAME(c.name) + ' IS NULL)
    AND (SELECT COUNT(*) FROM ' + QUOTENAME(s.name) + '.' + QUOTENAME(t.name) + ') > 1 PRINT ''' + s.name + '.' + t.name + '.' + REPLACE(c.name, '''', '''''') + ''''
    from sys.columns c
    inner join sys.tables t ON c.object_id = t.object_id
    inner join sys.schemas s ON s.schema_id = t.schema_id
    where c.is_nullable = 1 AND c.is_computed = 0
    order by s.name, t.name, c.name;

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

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

ฉันรู้ว่าประสิทธิภาพไม่ใช่สิ่งที่ DBA คิดเกี่ยวกับสิ่งนั้นมากนัก แต่คุณสามารถโยนหน่วยความจำและพลังงานตัวประมวลผลจำนวน จำกัด ได้ในโซลูชันซึ่งเป็นจุดที่คุณจะต้องเริ่มคิดถึงการออกแบบเชิงตรรกะและกายภาพ .

นอกจากนี้โปรดทราบว่านี่เป็นเพียงสำหรับ RDBMS ที่แท้จริงและฉันอ้างอิงส่วนทางเทคนิคของคำตอบของฉันที่อยู่นอก SQL Server T-SQL ที่แสดงรายการเพื่อค้นหาคอลัมน์ที่ไม่มีค่าได้โดยไม่มีค่า null นั้นมาจาก SQL Server


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