ข้อมูลการกำหนดค่า: ตารางแถวเดียวกับตารางคู่ค่าชื่อ


64

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

  1. ตารางแถวเดียว

      CompanyName  |  StartFullScreen  |  RefreshSeconds  |  ...
    ---------------+-------------------+------------------+--------
      ACME Inc.    |        true       |       20         |  ...
    
  2. ค่าชื่อคู่โต๊ะ

      ConfigOption   |   Value
    -----------------+-------------
     CompanyName     | ACME Inc.
     StartFullScreen | true (or 1, or Y, ...)
     RefreshSeconds  | 20
     ...             | ...
    

ฉันเคยเห็นตัวเลือกทั้งสองในป่าและทั้งสองมีข้อดีและข้อเสียที่เห็นได้ชัดเช่น:

  • ตารางแถวเดี่ยว จำกัด จำนวนตัวเลือกการกำหนดค่าที่คุณสามารถมีได้ (เนื่องจากจำนวนคอลัมน์ในแถวนั้น จำกัด ) ตัวเลือกการกำหนดค่าเพิ่มเติมทุกตัวต้องเปลี่ยนแปลง DB schema
  • ในตารางชื่อคู่ค่าทุกอย่าง "พิมพ์สตริง" (คุณต้องเข้ารหัส / ถอดรหัสพารามิเตอร์บูลีน / วันที่ / ฯลฯ ของคุณ)
  • (อื่น ๆ อีกมากมาย)

มีความเห็นพ้องกันบ้างในชุมชนการพัฒนาเกี่ยวกับตัวเลือกที่เหมาะสมกว่า?


2
ไม่มีเหตุผลที่วิธีการ 'แนวตั้ง' ไม่สามารถมีชนิดข้อมูลที่แตกต่างกันได้ เพิ่มคอลัมน์ int, float และ text ต่อแถว บันทึก / โหลดค่าจากมันโดยใช้ฟังก์ชันเฉพาะประเภทเช่น 'SaveConfigInt (' field ', n)'
GrandmasterB

4
มีคำถาม StackOverflow ที่ยอดเยี่ยมถามเกี่ยวกับเรื่องนี้และคำตอบยอดนิยมให้ข้อดีและข้อเสียกับทั้งสองวิธี stackoverflow.com/questions/2300356/…
Kevin

1
วิธีที่ 3: คอลัมน์เดี่ยว / แถวเดี่ยวที่มีรูปแบบการแลกเปลี่ยนข้อมูลอย่างง่าย ๆ เช่น JSON หรือ YAML รวมข้อดีจากทั้งสองวิธีเข้าด้วยกัน
schlamar

สิ่งที่เกี่ยวกับการใช้ตารางแบบแถวเดียวที่มีข้อมูลที่ซับซ้อนที่มี xml / json เช่น <config> <CompanyName> ACME Inc. </CompanyName> <StartFullScreen> true </StartFullScreen> 20<RefreshSeconds> </RigreshSeconds> </config> และ ตรวจสอบวัตถุในชั้นธุรกิจหรือไม่
จอห์น

1
@ จอห์น: ความคิดที่ดีถ้าจำเป็นต้องมีโครงสร้างแบบลำดับชั้น หากไม่เป็นเช่นนั้นก็เป็นเพียงตัวเลือกที่ 2 พร้อมความซับซ้อนที่เพิ่มขึ้น
Heinzi

คำตอบ:


15

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

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


จะเป็นอย่างไรถ้าข้อมูลที่จะจัดเก็บนั้นผู้ใช้กำหนดเอง เช่นคิดว่า UI ที่ผู้ใช้สามารถสร้าง "ฟิลด์" โดยการระบุป้ายฟิลด์ประเภทของข้อมูลที่จะเก็บ ฯลฯ ที่จะหมายถึงการดำเนินการคำสั่ง DDL จากรหัส คุณจะยังคงใช้ตัวเลือก 1 หรือไม่
devanalyst

1
@devanalyst ไม่หากข้อมูลสามารถเปลี่ยนจากองค์ประกอบหนึ่งไปเป็นอีกองค์ประกอบได้มันจะไม่มีเหตุผลที่จะพยายามสร้างตารางคงที่เพื่อเป็นตัวแทนของมัน ในกรณีนั้นจะเป็นการดีกว่าถ้าใช้ตัวเลือกที่สอง
Neil

12

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

ConfigOption   |   textValue    |   DateValue   |   NumericValue

ตัวเลือกที่ 1 มีสิทธิประโยชน์เพิ่มเติมที่คุณสามารถ "สลับ" การกำหนดค่าทั้งหมดได้อย่างง่ายดายโดยการเพิ่มActiveคอลัมน์


หากคุณกำลังจะไปช่วยให้การกำหนดค่าที่จะถูกปิดการใช้งาน (สำหรับตัวเลือกที่ 1) อย่างน้อยทำให้activatedOnการประทับเวลาเพื่อให้คุณสามารถบอกได้เมื่อมันถูกเปิดใช้งาน และถ้าคุณเลือกตัวเลือกที่ 2 ... จะเกิดอะไรขึ้นถ้าท้ายสุดของการจัดเก็บค่าในหลาย ๆคอลัมน์ (หรือมันเป็นออราเคิลซึ่งเป็นที่ว่างเปล่า
Clockwork-Muse

1
@ X-Zero การจัดเก็บ Configs หลายรายการมักจะทำเพื่อวัตถุประสงค์ในการทดสอบ แต่การประทับเวลาไม่สามารถทำได้ กำหนดค่าบำรุงรักษา, การเรียกร้องให้ได้รับค่าจะได้รู้ว่าสิ่งที่คอลัมน์ในการตรวจสอบถ้าคุณอยากจะคุณสามารถเพิ่มคอลัมน์สำหรับประเภทข้อมูล .. แต่ผมคิดว่ามีมากกว่าฆ่า ...
Morons

5
สคีมา EATV (เอนทิตี - แอตทริบิวต์ - ประเภท - ค่า) แบ่งฟอร์มปกติที่สาม คอลัมน์ประเภทจะเกี่ยวข้องกับคีย์หลักของตารางโดยทางอ้อมผ่านคอลัมน์ค่าที่คอลัมน์ประเภทอธิบาย นอกจากนี้การจัดเก็บประเภทไดนามิกและการสร้างอินสแตนซ์ไม่ได้ช่วยอะไรมากนัก ถ้าเมธอด GetConfigValue () สามารถคืนค่าชนิดใด ๆ ได้ก็จะต้องส่งคืนออบเจกต์ (หรือได้รับประเภทที่คาดหมายไว้) ซึ่งจะต้องได้รับการประเมินที่รันไทม์
KeithS

5
ตัวเลือกทุกครั้งที่ 1 ได้รับการติดตั้งในซอฟต์แวร์ที่ฉันเคยเห็นมันจะต้องถูกแปลงเป็นตัวเลือกที่ 2 ตัวเลือกที่ 2 นั้นง่ายต่อการดูแลรักษาเมื่อเวลาผ่านไปเพียงแค่สัมผัสอีกครั้ง ตัวเลือกที่ 1 นั้นรวดเร็วและง่ายต่อการใช้งาน แต่การบำรุงรักษาในช่วงเวลานั้นแย่มากเว้นแต่ซอฟต์แวร์ของคุณจะเล็กและไม่มีโอกาสเติบโต
Jimmy Hoffa

8

สำหรับฉันไม่ว่าคุณจะไปแถวเดียวหรือ EAV ขึ้นอยู่กับว่าคุณต้องการบริโภคมันอย่างไร

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

ข้อบกพร่องของมันคือมันมีเพียงโครงสร้างที่แทบจะไม่ต้องการให้คุณจัดการกับข้อมูลในแง่ร้าย ทุกการใช้งานของค่าการกำหนดค่าใด ๆ จะต้องคาดหวังว่าค่าจะไม่มีอยู่หรือไม่อยู่ในรูปแบบที่เหมาะสมและทำงานตามนั้นเมื่อไม่มี ค่าการกำหนดอาจไม่สามารถแยกวิเคราะห์เป็น double หรือ int หรือ char อาจเป็นโมฆะ อาจไม่มีแถวสำหรับค่าเลย วิธีที่รอบนี้มักจะต้องเป็นหนึ่งเดียวที่ถูกต้อง "เริ่มต้น" มูลค่าให้กับที่มีอยู่สำหรับค่าการตั้งค่าทั้งหมดของโดยเฉพาะอย่างยิ่งพิมพ์รหัส ( มากหายากมากขึ้นมักจะมีค่าเริ่มต้นเป็นเพียงเป็นปัญหาสำหรับรหัสบริโภคเป็นไม่มีเลย) หรือ เก็บ hardcoded dictionary ของค่าเริ่มต้น (ซึ่งจะต้องเปลี่ยนทุกครั้งที่มีการเพิ่มคอลัมน์ใหม่ทำให้ข้อได้เปรียบหลักของการจัดเก็บ EAV ดูน่าสนใจ)

แถวกว้างเดี่ยวค่อนข้างตรงกันข้าม คุณแมปกับอินสแตนซ์เดียวของวัตถุการกำหนดค่าด้วยเขตข้อมูล / คุณสมบัติสำหรับทุกค่าการกำหนดค่าที่มีอยู่ คุณรู้แน่ชัดว่าค่าเหล่านั้นควรเป็นประเภทใดในเวลารวบรวมและคุณ "ล้มเหลวเร็ว" ใน DAL หากไม่มีคอลัมน์กำหนดค่าหรือไม่มีค่าประเภทที่เหมาะสม เกี่ยวกับปัญหาการเรียกคืน / การทำไฮเดรชั่น

ข้อเสียเปรียบหลักคือการเปลี่ยนแปลงโครงสร้างจำเป็นสำหรับค่าใหม่แต่ละค่า คอลัมน์ DB ใหม่คอลัมน์ใหม่ใน DAL (ทั้งการแมปหรือการสืบค้น SQL / SPs) คอลัมน์โดเมนใหม่ทั้งหมดที่จำเป็นในการทดสอบการใช้งานอย่างถูกต้อง

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

ในระยะสั้น EAV schema เพื่อจัดเก็บการกำหนดค่าจริงๆไม่ได้แก้ปัญหาที่อ้างว่าจะแก้ปัญหาและส่วนใหญ่ของการแก้ไขปัญหาที่นำเสนอละเมิด DRY


3

โดยเฉพาะสำหรับค่าการกำหนดค่าฉันจะพูด - ไปกับแถวเดียว นอกจากว่าคุณกำลังจะผ่านการพัฒนาคอลัมน์เหล่านั้นจะเปลี่ยนไปบ่อยแค่ไหน?

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

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


2

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

หากลูกค้าของคุณไม่สามารถประมวลผลชิ้นส่วน JSON ให้รับลูกค้าใหม่


1

ข้อดีแถวเดี่ยว: กำหนดไว้อย่างดี ข้อด้อย: การเปลี่ยนการกำหนดค่าอาจเป็นความเจ็บปวด การย้ายฐานข้อมูล ฯลฯ

ข้อดีของ Entity-Value: ความยืดหยุ่นสูงรองรับการปรับแต่งค่าของคุณ จุดด้อย: Referential Integrity? ตรวจสอบเพิ่มเติมในรหัสของคุณเพื่อดูว่ามีสถานที่ให้บริการอยู่ก่อนที่คุณจะทำอะไรกับมัน

ฉันจะใช้วิธีที่ 2 ได้รับการสนับสนุนโดยฐานข้อมูลที่ไม่เกี่ยวข้องเช่น Mongo หากมีบางสิ่งที่คุณมั่นใจได้ว่าเป็นการเปลี่ยนแปลง


1

ใช้ทั้งสอง!

จัดเรียงตัวเลือกสิ่งที่สามารถมีได้หลายอินสแตนซ์และตัวเลือกใดเป็นแบบทั่วไป

ตารางแถวเดียว(การกำหนดค่า)

  id  |  company_name  |  start_fullscreen  |  refresh_seconds  |  ...
------+----------------+--------------------+-------------------+-------
  4   |  ACME Inc.     |  true              |  20               |  ...

ตารางค่าชื่อคู่(ตัวเลือก)

  name             |  value          | update_time  
-------------------+-----------------+--------------
  generic_option_1 |  Option 1 Value | timestamp    
  generic_option_2 |  Option 2 Value | timestamp    
  generic_option_3 |  Option 3 Value | timestamp    
  configuration    |  4              | timestamp    
  ...              |  ...            | ...          

ฉันคิดว่ามันยืดหยุ่นกว่านี้

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