การออกแบบและการปฏิบัติเพื่อป้องกันรายการ null ที่ผิดพลาดจากฐานข้อมูล


9

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

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

มีสถาปัตยกรรมที่ดีหรือหลักการออกแบบเพื่อจัดการกับรายการที่หายาก แต่เป็นไปได้nullหรือไม่?

โซลูชันควรเป็นไปได้ที่จะนำไปใช้กับ Java แต่ฉันไม่ได้ใช้แท็กเพราะฉันคิดว่าปัญหาค่อนข้างไม่เชื่อเรื่องภาษา


ความคิดบางอย่างที่ฉันมี:

ใช้ NOT NULL

ที่ง่ายที่สุดคือการใช้ข้อ จำกัด NOT NULL ในฐานข้อมูล

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

อย่างไร้เดียงสาขึ้นอยู่กับ NullPointerException

ฉันสามารถใช้ข้อมูลราวกับว่าฉันคาดหวังว่ามันจะอยู่ที่นั่นเสมอ (และนั่นควรจะเป็นอย่างนั้นจริง ๆ ) และจับ NPE ที่ได้ในระดับที่เหมาะสม (เช่นเพื่อให้การประมวลผลของรายการปัจจุบันหยุดลง แต่ไม่ใช่ความคืบหน้าการประมวลผลทั้งหมด ) นี่คือหลักการ "ล้มเหลวเร็ว" และฉันมักชอบมัน หากเป็นข้อบกพร่องอย่างน้อยฉันจะได้รับ NPE ที่บันทึกไว้

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

ตรวจสอบnullก่อนการเข้าถึงแต่ละครั้งและโยนข้อยกเว้นที่กำหนดเอง

ข้อยกเว้นที่กำหนดเองจะให้ฉันตัดสินใจการกระทำที่ถูกต้องตามข้อยกเว้นดังนั้นนี่จึงเป็นวิธีที่จะไป

แต่ถ้าฉันลืมตรวจสอบที่ไหนสักแห่ง? นอกจากนี้ฉันยังยุ่งเหยิงรหัสของฉันด้วยการตรวจสอบ null ซึ่งไม่เคยคาดหวังหรือไม่ค่อยเกิดขึ้น (และแน่นอนว่าไม่ใช่ส่วนหนึ่งของการไหลของตรรกะทางธุรกิจ)

หากฉันเลือกที่จะไปทางนี้รูปแบบใดที่เหมาะสมที่สุดสำหรับแนวทาง


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

แก้ไข:

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


5
"บางคอลัมน์อาจเป็นโมฆะ แต่ในบริบทการประมวลผลในปัจจุบันที่เป็นข้อผิดพลาด ... ในกรณีที่การแทรกจะใส่ค่า NULL ลงในตารางฉันไม่ต้องการให้การแทรกล้มเหลว" ข้อกำหนดทั้งสองนี้คือ ซึ่งตรงกันข้าม เป็นไปไม่ได้ที่จะหาทางแก้ปัญหาจนกว่าคุณจะผ่อนคลายหนึ่งในสองเงื่อนไขนี้
Kilian Foth

@KilianFoth การผ่อนคลายของฉันคือข้อผิดพลาดในบริบท "การประมวลผลปัจจุบัน" นั้นรุนแรงน้อยกว่าเมื่อแทรก ดังนั้นฉันจึงยอมรับข้อผิดพลาดในการประมวลผลที่หายาก แต่ฉันต้องการมีการออกแบบที่แข็งแกร่งเพื่อจัดการกับข้อผิดพลาดเหล่านั้น นั่นเป็นเหตุผลที่ไม่เป็นโมฆะซึ่งเป็นวิธีแก้ปัญหาที่ดีเป็นไปไม่ได้ที่นี่
jhyot

1
หากคุณดำเนินการเกี่ยวกับการยอมรับข้อผิดพลาดจำนวนมากผู้สร้างข้อผิดพลาดนั้นจะไม่แก้ไขข้อผิดพลาดเหล่านั้น หากข้อความที่ยุ่งเหยิงของพวกเขาประสบความสำเร็จพวกเขาจะต้องทำสิ่งใดเพื่อแก้ไข คุณคิดว่าแข็งแกร่งไม่ล้มเหลว แต่ยอมรับข้อมูลที่ไม่ดี
Tulains Córdova

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

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

คำตอบ:


9

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

หากคุณใช้ ORM คุณจะต้องทำการตรวจสอบ null ทั้งหมดก่อนที่จะประมวลผลแต่ละระเบียน ฉันขอแนะนำrecordIsValid(recordData)วิธีการแบบ -type วิธีที่คุณสามารถ (อีกครั้ง) ให้การตรวจสอบโมฆะและตรรกะการตรวจสอบอื่น ๆ ทั้งหมดในที่เดียว ฉันจะไม่ตรวจสอบโมฆะใด ๆ กับส่วนที่เหลือของตรรกะการประมวลผลของคุณ


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

และถ้าคุณเปลี่ยนออมของคุณแล้วจะเป็นอย่างไร? ดีกว่าที่จะปกป้องที่แหล่งที่มา (ดูคำตอบของ Doc Brown)
Robbie Dee

@ RobbieDee: ไม่เป็นไร หากคุณต้องเขียนรหัสการแมปใหม่การตรวจสอบแบบ null จะอยู่ที่นั่นและคุณแก้ไขเป็นส่วนหนึ่งของการเขียนใหม่หรือคุณมีวิธีแยกต่างหากที่ดำเนินการตรวจสอบแบบโมฆะในวัตถุธุรกิจของคุณดังนั้นจึงไม่จำเป็นต้องเขียนซ้ำ และตามที่ Doc Brown ให้ความหมายบางครั้งสิ่งสำคัญคือการสังเกตว่าข้อมูลขาดหายไปแทนที่จะทำการคัดสรรข้อเท็จจริงโดยใช้ค่าเริ่มต้น
TMN

ที่ควรเกิดขึ้นต่อไปในกระแส ETL คุณยังคงมีความเสี่ยงในการทำซ้ำด้วยวิธีนี้
Robbie Dee

6

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

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


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

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

5

ในเรื่องเกี่ยวกับประโยคนี้ในคำถาม:

สิ่งนี้จะ "เกิดขึ้นตามหลักวิชา" ไม่ควรเกิดขึ้นดังนั้นหากมันชี้ไปที่ข้อมูลที่ไม่ดีหรือจุดบกพร่องในรหัส

ฉันชื่นชมคำพูดนี้เสมอ (ความอนุเคราะห์จากบทความนี้ ):

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

โดยทั่วไป: ดูเหมือนว่าคุณรับรองกฎหมายของ Postel "จงระมัดระวังในสิ่งที่คุณส่งให้มีอิสระในสิ่งที่คุณยอมรับ" ในขณะที่ดีในทางทฤษฎีในทางปฏิบัติ "หลักการความแข็งแกร่ง" นี้นำไปสู่ซอฟต์แวร์ที่ไม่แข็งแกร่งอย่างน้อยในระยะยาว - และบางครั้งในระยะสั้นเช่นกัน (เปรียบเทียบกระดาษของ Eric Allman The Robustness Principle Reconsideredซึ่งเป็นการรักษาอย่างละเอียดมากของเรื่องแม้ว่าจะมุ่งเน้นไปที่กรณีการใช้โปรโตคอลเครือข่าย)

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

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

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

วิธีหนึ่งในการก้าวเท้าเลี่ยงปัญหาเหล่านี้ทั้งหมดคือการแทรกเลเยอร์ API ที่คุณควบคุมระหว่างโปรแกรมที่ออกการเขียนและฐานข้อมูลจริง

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

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


"หากคุณมีโปรแกรมที่ใส่ข้อมูลลงในฐานข้อมูลไม่ถูกต้องโปรแกรมเหล่านั้นจะเสียหายและจำเป็นต้องแก้ไข" มันเป็นทฤษฎีที่ยอดเยี่ยมเช่นกัน แต่ความจริงก็คือพวกเขาจะยังคงเพิ่มบันทึกในขณะที่บางคณะกรรมการยังคงถกเถียงกันว่าจะใช้ "NA" หรือ "ไม่มี"
JeffO

@JeffO: ไม่ควรมีคณะกรรมการที่ถกเถียงกันว่าจะเก็บ "NA", "None", NULL หรืออะไรอย่างอื่นในฐานข้อมูล ผู้มีส่วนได้เสียที่ไม่ใช่ด้านเทคนิคมีส่วนได้ส่วนเสียในสิ่งที่ข้อมูลออกมาจากฐานข้อมูลและวิธีการใช้ แต่ไม่ใช่ในการเป็นตัวแทนภายใน
Daniel Pryden

@DanielPryden: ที่งานล่าสุดของฉันเรามีคณะกรรมการพิจารณาโครงสร้าง (พร้อมคณะอนุกรรมการ DBA) ที่จะตรวจสอบการเปลี่ยนแปลงทางเทคนิคข้ามโดเมน ทางเทคนิคมาก แต่พวกเขาพบกันทุกสองสัปดาห์และถ้าคุณไม่ได้ให้รายละเอียดเพียงพอสำหรับพวกเขาพวกเขาจะเลื่อนการตัดสินใจจนกว่าคุณจะ ... ในการประชุมครั้งต่อไป การเปลี่ยนแปลงระบบที่ไม่น่ารำคาญส่วนใหญ่ที่ไม่ได้ประกอบด้วยการเพิ่มฟังก์ชั่นการทำงานผ่านรหัสใหม่อาจใช้เวลาเป็นเดือนหรือมากกว่านั้น
TMN

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

ในการตอบกลับความคิดเห็นเกี่ยวกับการได้รับการอนุมัติเพิ่มเติมสำหรับการเปลี่ยนแปลงประเภทนี้: จุดของฉันเกี่ยวกับค่าที่เป็น "ไม่ถูกต้อง" สันนิษฐานว่าค่าที่อนุญาตมีการบันทึกไว้แล้วบางแห่ง - นั่นคือเหตุผลที่ OP บอกว่าค่าเหล่านี้ หากสคีมาของฐานข้อมูลถูกระบุให้อนุญาตค่าดังนั้นค่านั้นไม่ใช่ข้อผิดพลาด ประเด็นก็คือถ้าคุณมีข้อมูลที่ไม่ตรงกับสคีมาของคุณมีบางอย่างที่เสียหาย: ลำดับความสำคัญของคุณคือการทำให้ข้อมูลและสคีมาตรงกัน ขึ้นอยู่กับทีมที่อาจเกี่ยวข้องกับการเปลี่ยนแปลงข้อมูลสคีมาหรือทั้งสองอย่าง
Daniel Pryden

2

" มีสถาปัตยกรรมที่ดีหรือหลักการออกแบบเพื่อจัดการกับรายการ null ที่หายาก แต่เป็นไปได้หรือไม่ "

คำตอบง่ายๆ - ใช่

ETL

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

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

มาร์ท / พื้นที่เก็บข้อมูล

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

ค่าเริ่มต้น

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

ล้มเหลว แต่เนิ่นๆ

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


+1 นี่คือสิ่งที่ฉันจะทำรวบรวมข้อมูลทั้งหมดและสร้างชุดข้อมูลที่ถูกต้องเพื่อให้แอปพลิเคชันของคุณประมวลผล
Kwebble

1

เมื่อใดก็ตามที่กรณีการใช้งานของคุณจะช่วยให้การเปลี่ยนโมฆะได้อย่างปลอดภัยโดยค่าเริ่มต้นที่ดีที่คุณสามารถทำแปลงในส่วนSELECTคำสั่ง SQL ใช้หรือISNULL COALESCEดังนั้นแทนที่จะ

 SELECT MyColumn FROM MyTable

หนึ่งสามารถเขียน

 SELECT ISNULL(MyColumn,DefaultValueForMyColumn) FROM MyTable

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

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

จากประสบการณ์ของฉันเองฉันรู้ว่าการใช้ ISNULL สามารถทำงานได้ดีอย่างน่าประหลาดใจ - ในอดีตฉันต้องรักษาแอปพลิเคชันแบบดั้งเดิมซึ่งผู้พัฒนาดั้งเดิมลืมที่จะเพิ่มข้อ จำกัด NULL ไม่ให้คอลัมน์จำนวนมากและเราไม่สามารถเพิ่มข้อ จำกัด เหล่านั้นได้ในภายหลัง ด้วยเหตุผลบางอย่าง แต่ใน 99% ของทุกกรณี 0 เป็นค่าเริ่มต้นสำหรับคอลัมน์ตัวเลขและสตริงว่างเป็นค่าเริ่มต้นสำหรับคอลัมน์ข้อความเป็นที่ยอมรับอย่างสมบูรณ์


ในขณะที่ใช้งานได้คุณจะต้องทำซ้ำรหัสป้องกันสำหรับแต่ละ SELECT วิธีที่ดีกว่าคือการกำหนดค่าเริ่มต้นสำหรับคอลัมน์เมื่อใส่ค่า NULL แม้ว่าสิ่งนี้อาจไม่สามารถทำได้ / เป็นที่ต้องการด้วยเหตุผลหลายประการ
Robbie Dee

@ RobbieDee: ขอบคุณสำหรับคำพูดนั้นฉันเปลี่ยนคำตอบตามนั้น อย่างไรก็ตามถ้านี่คือ "ไกลดีกว่า" เป็นที่ถกเถียงกัน เมื่อรหัส CRUD อยู่ในที่เดียวรหัสป้องกันที่ซ้ำกันอาจมีปัญหาไม่มาก และหากไม่เป็นเช่นนั้นจะมีการทำสำเนารหัสล่วงหน้าอยู่แล้ว
Doc Brown

การดำเนินงาน CRUD อย่างง่ายนั้นเหมาะอย่างยิ่ง แต่ในโลกแห่งความเป็นจริงระบบมักจะมีมุมมอง UI ที่ซับซ้อนผู้ใช้สร้างตัวช่วยสร้างข้อมูลรายงานและอื่น ๆ แต่เมื่อคุณชี้ให้เห็นค่าเริ่มต้นจะต้องอยู่ที่นั่นตั้งแต่เริ่มต้นขึ้นไปหรืออย่างน้อยก็ต้องการการแปลง สิ่งที่คุณได้อธิบายไว้อาจเป็นที่นิยมในการพัฒนาบราวน์ฟิลด์
Robbie Dee

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

1

OP กำลังสันนิษฐานคำตอบว่ากฎเกณฑ์ทางธุรกิจที่คู่กันมีรายละเอียดทางเทคนิคของฐานข้อมูล

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

นี่คือกฎทางธุรกิจทั้งหมด กฎเกณฑ์ทางธุรกิจไม่สนใจเรื่อง null-se สำหรับทุกอย่างมันรู้ว่าฐานข้อมูลอาจมีค่าเป็นโมฆะ, 9999, "BOO!" ... มันเป็นเพียงค่าอีกค่า ใน RDBMS นั้น null มีคุณสมบัติที่น่าสนใจและการใช้ที่ไม่เหมือนใครคือ moot

สิ่งเดียวที่สำคัญคือ "null-ness" หมายถึงวัตถุทางธุรกิจที่กำหนด ...

มีสถาปัตยกรรมที่ดีหรือหลักการออกแบบเพื่อจัดการกับรายการ null ที่หายาก แต่เป็นไปได้หรือไม่?

ใช่.

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

การโยนข้อยกเว้นเมื่อดึงข้อมูลไม่สมเหตุสมผล

คำถามคือ"ฉันควรเก็บข้อมูล" ไม่ดี "หรือไม่ มันขึ้นอยู่กับ:

  • อาจมีการใช้ข้อมูลที่ไม่ถูกต้อง - ห้ามบันทึกวัตถุที่ไม่ถูกต้องหรือคอมโพสิตของวัตถุ ข้อมูลที่ซับซ้อน / ความสัมพันธ์ทางธุรกิจทั่วทุกสถานที่ ผู้ใช้สามารถทำหน้าที่ใด ๆ ตามเวลาที่กำหนดอาจใช้เอนทิตีธุรกิจนั้นในบริบทจำนวนหนึ่ง ไม่ทราบผลกระทบ (ถ้ามี) ของข้อมูลที่ไม่ถูกต้องในขณะนั้นข้อมูลนั้นขึ้นอยู่กับการใช้งานในอนาคต ไม่มีข้อมูลรวม / กระบวนการเดียวของข้อมูลนั้น
  • ไม่สามารถดำเนินการหากมีข้อมูลไม่ดี - อนุญาตให้บันทึกข้อมูลที่ไม่ดี อย่างไรก็ตามขั้นตอนถัดไปในกระบวนการไม่สามารถดำเนินต่อไปได้จนกว่าทุกอย่างจะถูกต้อง ตัวอย่างเช่นการทำภาษีเงินได้ของคน ๆ หนึ่ง เมื่อดึงจากฐานข้อมูลซอฟต์แวร์จะชี้ให้เห็นข้อผิดพลาดและไม่สามารถส่งไปยัง IRS โดยไม่ตรวจสอบความถูกต้อง

0

มีหลายวิธีในการจัดการค่า null ดังนั้นเราจะย้ายจากเลเยอร์ฐานข้อมูลไปยังชั้นแอปพลิเคชัน


เลเยอร์ฐานข้อมูล

คุณสามารถห้าม nulls ; แม้ว่าที่นี่จะทำไม่ได้

คุณสามารถกำหนดค่าเริ่มต้นบนพื้นฐานต่อคอลัมน์:

  • มันต้องการให้คอลัมน์ขาดหายไปจากinsertดังนั้นจึงไม่ครอบคลุมถึงการแทรก null อย่างชัดเจน
  • มันป้องกันการตรวจจับจากแถวที่insertคอลัมน์นี้พลาดอย่างผิดพลาด

คุณสามารถกำหนดค่าทริกเกอร์ดังนั้นเมื่อแทรกค่าที่หายไปจะถูกคำนวณโดยอัตโนมัติ:

  • ต้องมีข้อมูลที่จำเป็นในการคำนวณนี้อยู่
  • มันจะช้าลง insert

ชั้นค้นหา

คุณสามารถข้ามแถวที่มีความไม่สะดวกnullอยู่:

  • มันลดความซับซ้อนของตรรกะหลัก
  • มันป้องกันการตรวจจับ "แถวที่ไม่ดี" ดังนั้นกระบวนการอื่นจึงจำเป็นต้องมีการตรวจสอบ
  • มันต้องการให้แต่ละแบบสอบถามเป็นเครื่องมือ

คุณสามารถระบุค่าเริ่มต้นในแบบสอบถามได้:

  • มันลดความซับซ้อนของตรรกะหลัก
  • มันป้องกันการตรวจจับ "แถวที่ไม่ดี" ดังนั้นกระบวนการอื่นจึงจำเป็นต้องมีการตรวจสอบ
  • มันต้องการให้แต่ละแบบสอบถามเป็นเครื่องมือ

หมายเหตุ: การสร้างคำถามแต่ละรายการนั้นไม่จำเป็นต้องเป็นปัญหาหากคุณมีวิธีการสร้างโดยอัตโนมัติ


แอพลิเคชันเลเยอร์

คุณสามารถตรวจสอบตารางที่ต้องห้ามล่วงหน้าได้null :

  • มันลดความซับซ้อนของตรรกะหลัก
  • มันช่วยปรับปรุงเวลาที่ล้มเหลว
  • มันต้องมีการตรวจสอบล่วงหน้าและตรรกะของแอปพลิเคชัน

คุณสามารถขัดจังหวะการประมวลผลเมื่อพบสิ่งต้องห้ามnull:

  • มันหลีกเลี่ยงการทำซ้ำความรู้ของคอลัมน์ที่สามารถnullและไม่ได้
  • มันยังค่อนข้างง่าย (เพียงเช็ค + คืน / โยน)
  • มันต้องการให้กระบวนการของคุณกลับมาทำงานต่อได้ (หากคุณได้ส่งอีเมลไปแล้วไม่ต้องการส่งสองครั้งหรือเป็นร้อยครั้ง!)

คุณสามารถข้ามแถวได้เมื่อพบสิ่งต้องห้ามnull:

  • มันหลีกเลี่ยงการทำซ้ำความรู้ของคอลัมน์ที่สามารถnullและไม่ได้
  • มันยังค่อนข้างง่าย (เพียงเช็ค + คืน / โยน)
  • ไม่ต้องการให้กระบวนการของคุณทำงานต่อได้

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


ด้วยสถานการณ์ของคุณฉันจะจัดการกับสถานการณ์ที่แอปพลิเคชันและรวม:

  • ขัดจังหวะและแจ้งเตือน
  • ข้ามและแจ้งเตือน

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

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

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


-1

Null สามารถจัดการได้ในการแปลหรือการแมปประเภทฐานข้อมูลกับชนิดภาษา ตัวอย่างเช่นใน C # ต่อไปนี้เป็นวิธีการทั่วไปที่จัดการ null สำหรับคุณทุกประเภท:

public static T Convert<T>(object obj)
        {
            if (obj == DBNull.Value)
            {
                return default(T);
            }

            return (T) obj;
        }

public static T Convert<T>(object obj, T defaultValue)
        {
            if (obj == DBNull.Value)
            {
                T t = defaultValue;
                return t;
            }

            return (T) obj;
        }

หรือหากคุณต้องการดำเนินการ ...

 public static T Convert<T>(object obj, T defaultValue)
        {
            if (obj == DBNull.Value)
            {
                //Send an Alert, we might want pass in the name
                //of column or other details as well
                SendNullAlert();
                //Set it to default so we can keep processing
                T t = defaultValue;
                return t;
            }

            return (T) obj;
        }

จากนั้นในการแมปในกรณีนี้กับออบเจ็กต์ประเภท "ตัวอย่าง" เราจะจัดการ null สำหรับคอลัมน์ใด ๆ :

public class SampleMapper : MapperBase<Sample>
    {
        private const string Id = "Id";
        private const string Name = "Name";
        private const string DataValue = "DataValue";
        private const string Created = "Created";

        protected override Sample Map(IDataRecord record)
        {
            return new Sample(
                Utility.Convert<Int64>(record[Id]),
                Utility.Convert<String>(record[Name]),
                Utility.Convert<Int32>(record[DataValue]),
                Utility.Convert<DateTime>(record[Created])
                );
        }
    }

ในที่สุดคลาสการแมปทั้งหมดสามารถสร้างขึ้นโดยอัตโนมัติตามแบบสอบถาม SQL หรือตารางที่เกี่ยวข้องโดยดูที่ชนิดข้อมูล SQL และแปลเป็นประเภทข้อมูลเฉพาะของภาษา นี่คือสิ่งที่ ORM จำนวนมากทำเพื่อคุณโดยอัตโนมัติ โปรดทราบว่าฐานข้อมูลบางประเภทอาจไม่มีการแมปโดยตรง (Geo-spatial colunms ฯลฯ ) และอาจต้องการการจัดการพิเศษ


ถ้ามีคนต้องการที่จะโพสต์รุ่นเทียบเท่า Java ที่จะดี ...
จอน Raynor

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

อ๊ะฉันจะอัพเดทคำตอบของฉันตามนี้
Jon Raynor

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