วิธีการออกแบบฐานข้อมูลสำหรับฟิลด์ที่ผู้ใช้กำหนด?


145

ความต้องการของฉันคือ:

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

ข้อมูลอื่น ๆ:

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

ตัวเลือก:

  1. สร้างตารางขนาดใหญ่ด้วย StringValue1, StringValue2 ... IntValue1, IntValue2, ... ฯลฯ ฉันเกลียดความคิดนี้ แต่จะพิจารณาถ้ามีใครสามารถบอกฉันได้ดีกว่าความคิดอื่น ๆ และทำไม

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

  3. สร้างตารางเดียวที่มี UDFName, UDFDataType และ Value เมื่อเพิ่ม UDF ใหม่ให้สร้างมุมมองที่ดึงข้อมูลนั้นและแยกวิเคราะห์ลงในประเภทที่ระบุ รายการที่ไม่ตรงกับเกณฑ์การแยกวิเคราะห์จะส่งคืนค่า NULL

  4. สร้างตาราง UDF หลายตารางต่อหนึ่งประเภทข้อมูล ดังนั้นเราจึงมีตารางสำหรับ UDFStrings, UDFDates, ฯลฯ อาจทำเช่นเดียวกับ # 2 และสร้างมุมมองอัตโนมัติเมื่อใดก็ตามที่มีการเพิ่มฟิลด์ใหม่

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

  6. อื่น ๆ อีก?


7
Martin Fowler แนะนำ 2 (schema ที่ผู้ใช้สามารถอัปเดตได้) หรือ 5 (LOB XML ที่จัดทำดัชนีไว้): martinfowler.com/bliki/UserDefinedField.html
Neil McGuigan

ดูเพิ่มเติมคำถาม StackOverflow บนschemas ฐานข้อมูลแบบไดนามิก
FloverOwe

คำตอบ:


49

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

ข้อดี:

  1. เนื่องจากคุณระบุว่า UDF บางตัวมีค่าสำหรับส่วนเล็ก ๆ ของชุดข้อมูลโดยรวมตารางแยกต่างหากจะให้ประสิทธิภาพที่ดีที่สุดเนื่องจากตารางนั้นจะมีขนาดใหญ่เท่าที่จำเป็นต้องให้การสนับสนุน UDF เช่นเดียวกันถือเป็นจริงสำหรับดัชนีที่เกี่ยวข้อง

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

  3. คุณสามารถใช้ชื่อตาราง / คอลัมน์ที่แสดงถึงข้อมูลที่แท้จริง

  4. คุณมีการควบคุมที่สมบูรณ์ในการใช้ชนิดข้อมูลตรวจสอบข้อ จำกัด ค่าเริ่มต้นและอื่น ๆ เพื่อกำหนดโดเมนข้อมูล อย่าดูถูกดูแคลนประสิทธิภาพการทำงานที่เกิดจากการแปลงชนิดข้อมูลแบบ on-the-fly ข้อ จำกัด ดังกล่าวยังช่วยให้เครื่องมือเพิ่มประสิทธิภาพข้อความค้นหา RDBMS พัฒนาแผนมีประสิทธิภาพมากขึ้น

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

จุดด้อย:

  1. สิ่งนี้สามารถสร้างตารางจำนวนมาก การบังคับให้แยกสคีมาและ / หรืออนุสัญญาการตั้งชื่อจะช่วยลดปัญหานี้ได้

  2. จำเป็นต้องมีรหัสแอปพลิเคชันเพิ่มเติมเพื่อใช้งานคำจำกัดความและการจัดการ UDF ฉันคาดหวังว่านี่ยังคงเป็นรหัสน้อยกว่าตัวเลือกเดิม 1, 3 และ 4

ข้อควรพิจารณาอื่น ๆ :

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

     'red', 'large', 45.03 

    ค่อนข้างมากกว่า

     NULL, 'medium', NULL

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

  2. หากคุณกดกำแพงประสิทธิภาพจาก UDF ที่มีประชากรมากและใช้บ่อยควรพิจารณาให้รวมไว้ในตารางต้นแบบ

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


1
รายการตรวจสอบ! ภายในมุขระหว่างฉันและฟิลฉันหวังว่ามันจะไม่ขัดกับกฎ
GunnerL3510

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

ฉันทำงานกับตารางที่มี UDF / ลงวันที่ฉันใช้วิธีนี้stackoverflow.com/a/123481/328968เพื่อรับค่าล่าสุด
ปีเตอร์

22

ผมได้เขียนเกี่ยวกับปัญหานี้มาก โซลูชันที่พบบ่อยที่สุดคือ antipattern Entity-Attribute-Value ซึ่งคล้ายกับที่คุณอธิบายในตัวเลือก # 3 หลีกเลี่ยงการออกแบบนี้เช่นภัยพิบัติ

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

คุณสามารถอ่านบทความที่น่าสนใจจาก 2009 เกี่ยวกับวิธีแก้ไขปัญหานี้ได้ที่นี่: http://backchannel.org/blog/friendfeed-schemaless-mysql

หรือคุณสามารถใช้ฐานข้อมูลเชิงเอกสารซึ่งคาดว่าคุณจะมีฟิลด์ที่กำหนดเองต่อเอกสาร ฉันเลือกSolr


1
คุณช่วยอธิบายได้ไหมว่าทำไมฉันควรหลีกเลี่ยงตัวเลือก # 3 ฉันดูตัวอย่างบางส่วนของคุณ แต่สิ่งเหล่านี้ไม่เหมือนกับสิ่งที่ฉันพยายามทำ ฉันต้องการที่เก็บข้อมูลเพิ่มเติมไม่ใช่ที่สำหรับเก็บคุณสมบัติทั้งหมด
Rachel

2
สำหรับ starters คุณจะสร้างแอททริบิวต์ว่าไม่เป็น NULL? คุณจะสร้างแอตทริบิวต์ UNIQUE อย่างไรโดยไม่สร้างแอตทริบิวต์ทั้งหมด UNIQUE มันไปจากที่นั่น คุณจะเขียนโค้ดแอปพลิเคชันเพื่อให้ฟีเจอร์ที่ RDBMS จัดเตรียมไว้ให้คุณแล้วจนถึงจุดที่ต้องเขียนคลาสการแม็พบางประเภทเพื่อใส่เร็กคอร์ดเอนทิตีแบบโลจิคัลแล้วดึงกลับคืนมา
Bill Karwin

2
คำตอบสั้น ๆ คือ "อย่าผสมข้อมูลกับข้อมูลเมตา" การสร้างคอลัมน์ varchar สำหรับfieldnameหรือtablenameเก็บตัวระบุข้อมูลเมตาเป็นสตริงข้อมูลและนั่นเป็นจุดเริ่มต้นของปัญหามากมาย โปรดดูen.wikipedia.org/wiki/Inner-platform_effect
Bill Karwin

2
@Thomas: ในการออกแบบดัชนีแบบกลับด้านคุณสามารถใช้สคีมามาตรฐานสำหรับประเภทข้อมูลและข้อ จำกัด เช่น UNIQUE และ FOREIGN KEY สิ่งเหล่านี้ไม่ทำงานเลยเมื่อคุณใช้ EAV ฉันยอมรับการใช้ดัชนีแบบกลับหัวกับ EAV ว่าเป็นลักษณะที่ไม่สัมพันธ์กันเพียงเพราะสนับสนุนคุณลักษณะที่แตกต่างกันต่อแถว แต่เป็นจุดประนีประนอม
Bill Karwin

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

10

ฉันอาจจะสร้างตารางโครงสร้างต่อไปนี้:

  • ชื่อ varchar
  • ประเภท varchar
  • จำนวนทศนิยมค่า
  • varchar StringValue
  • วันที่ DateValue

ประเภทของหลักสูตรที่แน่นอนขึ้นอยู่กับความต้องการของคุณ (และแน่นอนขึ้นอยู่กับ dbms ที่คุณใช้) คุณสามารถใช้ฟิลด์ NumberValue (ฐานสิบ) สำหรับ int's และ booleans คุณอาจต้องการประเภทอื่นเช่นกัน

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

คุณอาจต้องการข้อมูลเมตาบางประเภท ดังนั้นคุณจะจบลงด้วยสิ่งต่อไปนี้:

ตาราง UdfMetaData

  • int id
  • ชื่อ varchar
  • ประเภท varchar

ตาราง MasterUdfValues

  • int Master_FK
  • int MetaData_FK
  • จำนวนทศนิยมค่า
  • varchar StringValue
  • วันที่ DateValue

ไม่ว่าคุณจะทำอะไรฉันจะไม่เปลี่ยนโครงสร้างของตารางแบบไดนามิก มันเป็นฝันร้ายของการบำรุงรักษา ฉันจะไม่ใช้โครงสร้าง XML พวกเขาช้าเกินไป


ฉันชอบกลยุทธ์ของคุณและอาจเลือกใช้ แต่ในปี 2560 คุณจะเลือกใช้สิ่งที่แตกต่างออกไปหรือไม่? like json
maztt

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

นอกจากนั้นสิ่งที่ฉันเสนอในปี 2011 คือ IMHO ยังคงเป็นทางออกที่ถูกต้อง
Stefan Steinegger

10

ดูเหมือนว่าปัญหาที่อาจแก้ไขได้ดีกว่าโดยโซลูชันที่ไม่เกี่ยวข้องเช่น MongoDB หรือ CouchDB

ทั้งคู่อนุญาตให้มีการขยายคีมาแบบไดนามิกในขณะที่ช่วยให้คุณรักษาความสมบูรณ์ของ tuple ที่คุณต้องการ

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

คุณไม่สามารถกำหนดได้ว่าค่า Null หรือค่าที่หายไปเป็นรายการที่ถูกต้องหรือไม่มีรายการโดยไม่ต้องฝังกฎสคีมาในชั้นวัตถุของคุณ

คุณสูญเสียความสามารถในการจัดการสคีมาของคุณอย่างมีประสิทธิภาพ varchar 100 ตัวอักษรเป็นชนิดที่ถูกต้องสำหรับฟิลด์ "ค่า" หรือไม่ 200 ตัวอักษร? มันควรเป็น nvarchar แทนไหม? มันอาจเป็นการค้าขายที่ยากลำบากและสิ่งหนึ่งที่จบลงด้วยการที่คุณจะต้องวางข้อ จำกัด ในลักษณะที่มีการเปลี่ยนแปลงในชุดของคุณ บางอย่างเช่น "คุณสามารถมีได้เฉพาะฟิลด์ที่ผู้ใช้กำหนด x ฟิลด์เท่านั้นและแต่ละฟิลด์ต้องมีความยาวอักขระ y

ด้วยโซลูชันที่มุ่งเน้นเอกสารเช่น MongoDB หรือ CouchDB คุณจะคงคุณลักษณะทั้งหมดที่เชื่อมโยงกับผู้ใช้ภายในสิ่งอันดับเดียว เนื่องจากการเข้าร่วมไม่ใช่ปัญหาชีวิตจึงมีความสุขเพราะทั้งสองอย่างนี้ไม่เข้ากันได้ดีกับการเข้าร่วมแม้ว่าจะเป็นโฆษณา ผู้ใช้ของคุณสามารถกำหนดแอตทริบิวต์ได้มากเท่าที่ต้องการ (หรือคุณจะอนุญาต) ตามความยาวที่ไม่ยากในการจัดการจนกว่าจะถึงประมาณ 4MB

หากคุณมีข้อมูลที่ต้องการความสมบูรณ์ของระดับกรดคุณอาจพิจารณาแยกโซลูชันด้วยข้อมูลความสมบูรณ์สูงที่อาศัยอยู่ในฐานข้อมูลเชิงสัมพันธ์ของคุณและข้อมูลแบบไดนามิกที่อยู่ในร้านค้าที่ไม่เกี่ยวข้อง


6

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

ตัวเลือกที่ 1

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

ตัวเลือก 3,4,5

IMO, ข้อกำหนด 2, 3 และ 4 กำจัดการเปลี่ยนแปลงของ EAV ใด ๆ หากคุณต้องการสอบถามเรียงลำดับหรือทำการคำนวณข้อมูลนี้ EAV เป็นความฝันของคธูลูและทีมพัฒนาของคุณและฝันร้ายของ DBA EAV จะสร้างคอขวดในแง่ของประสิทธิภาพและจะไม่ให้ความสมบูรณ์ของข้อมูลที่คุณต้องการเพื่อรับข้อมูลที่คุณต้องการได้อย่างรวดเร็ว ข้อความค้นหาจะเปลี่ยนเป็นครอสแท็บไขว้อย่างรวดเร็ว

ตัวเลือก 2,6

ที่เหลือตัวเลือกเดียว: รวบรวมสเปคแล้วสร้างสคีมา

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

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

คอลัมน์กระจัดกระจาย


5
  1. สร้างตาราง UDF หลายตารางต่อหนึ่งประเภทข้อมูล ดังนั้นเราจึงมีตารางสำหรับ UDFStrings, UDFDates, ฯลฯ อาจทำเช่นเดียวกับ # 2 และสร้างมุมมองอัตโนมัติเมื่อใดก็ตามที่มีการเพิ่มฟิลด์ใหม่

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

คุณควรไปกับตารางเดียวที่มีหลายคอลัมน์เช่น:

varchar Name
varchar Type
decimal NumberValue
varchar StringValue
date DateValue

สิ่งนี้ควรเป็นข้อมูลที่ถูกต้องและมีการปรับปรุง คำตอบก่อนหน้านี้ในปี 2554 โดย Phil ไม่ได้เป็นคำแนะนำที่ดีอีกต่อไปในวันนี้ 2559
Yap Kai Lun Leon

ฉันจะได้รับตัวอย่างง่ายๆของการทำกระบวนการดังกล่าวใน sql?
Niroj

ขออภัยสำหรับการตอบกลับล่าช้า แต่คุณต้องการโครงสร้างฐานข้อมูลเหมือนกัน ฉันไม่ได้รับคุณ @Niroj คุณช่วยอธิบายรายละเอียดเหมือนสิ่งที่คุณต้องการได้ไหม
ผู้รับเหมา Amit

4

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

นี่เป็นโซลูชันที่ใช้ในแอพพลิเคชั่นขององค์กรการค้า

แก้ไข

ตัวเลือกอื่นที่พร้อมใช้งานในขณะนี้ แต่ไม่มีอยู่ (หรืออย่างน้อยก็ไม่ได้เป็นผู้ใหญ่) เมื่อคำถามที่ถามดั้งเดิมคือการใช้เขตข้อมูล json ในฐานข้อมูล

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

postgress

MySQL


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

UDF ที่แตกต่างกัน 1,300 สำหรับตารางเดียวหรือไม่ ผู้ใช้แต่ละคนมีตัวเลือกในการเพิ่ม UDF หรือผู้ใช้พลังงานบางประเภทเท่านั้นหรือไม่
Ophir Yoktan

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

2

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

ฉันถูกล่อลวงให้ลองใช้ XML คุณควรสามารถบังคับ schema กับเนื้อหาของ xml เพื่อตรวจสอบการพิมพ์ข้อมูลและอื่น ๆ ซึ่งจะช่วยเก็บชุดความแตกต่างของข้อมูล UDF ใน SQL Server เวอร์ชันใหม่คุณสามารถสร้างดัชนีในฟิลด์ XML ซึ่งควรช่วยในเรื่องประสิทธิภาพ (ดูhttp://blogs.technet.com/b/josebda/archive/2009/03/23/sql-server-2008-xml-indexing.aspx ) ตัวอย่าง


จริงๆแล้วฉันไม่ได้ดู XML เลย ข้อเสียที่สำคัญคือฉันจะต้องเรียนรู้วิธีการทำงานและวิธีการตรวจสอบกับมันและฉันได้ยินมาว่าการแสดงอาจแย่กว่าตัวเลือกอื่น ๆ
Rachel

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

2

หากคุณใช้ SQL Server อย่ามองข้ามประเภท sqlvariant มันค่อนข้างเร็วและควรทำงานของคุณ ฐานข้อมูลอื่นอาจมีบางสิ่งที่คล้ายคลึงกัน

ประเภทข้อมูล XML ไม่ดีสำหรับเหตุผลด้านประสิทธิภาพ หากคุณกำลังทำการคำนวณบนเซิร์ฟเวอร์คุณจะต้องยกเลิกการซีเรียลไลซ์เหล่านี้อยู่ตลอดเวลา

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


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

เพิ่งพบว่า sql_varients ไม่สามารถใช้กับประโยค LIKE ... นั่นเป็นข้อเสียอย่างใหญ่หลวงสำหรับฉัน แน่นอนถ้าฉันสร้างมุมมองสำหรับแต่ละ UDF แล้วฉันสามารถส่งไปยังประเภทข้อมูลที่เหมาะสมตาม SQL_VARIANT_PROPERTY (ค่า 'BaseType') ... ยังคงดูเหมือนว่าจะไม่ดีต่อประสิทธิภาพ
Rachel

คุณสามารถใช้ LIKE ได้ แต่คุณต้องเหวี่ยงค่าก่อน LIKE ใช้ได้กับ varchars เท่านั้นดังนั้นคุณต้องส่ง sql_variant ของคุณไปที่ varchar ตราบใดที่คุณรู้ว่า UDF ของคุณเป็น varchar (เช่นเนื่องจากประเภทถูกเก็บไว้ที่อื่น) คุณสามารถกรองแถวทั้งหมดของคุณไปยัง varchars จากนั้นส่งและเรียกใช้คิวรี LIKE ของคุณเช่น เลือก * จาก MyTable โดยที่ variant_type = 'v' Cast (variant_value เป็น varchar (สูงสุด)) เช่น 'Blah%' ด้วยวิธีนี้คุณไม่ได้แปลง ints และอื่น ๆ เป็นสตริงที่จะทำให้คุณช้าลง
Tim Rogers

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


1

ฉันจัดการสิ่งนี้ได้สำเร็จในอดีตโดยไม่ใช้ตัวเลือกเหล่านี้ (ตัวเลือก 6? :))

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

ใช้เอกสารเป็นตัวอย่าง: ฟิลด์ทั่วไปจะเป็นชื่อ, ประเภท, วันที่, ผู้เขียน ฯลฯ ซึ่งจะไปในตารางหลัก จากนั้นผู้ใช้จะกำหนดประเภทเอกสารพิเศษของตนเองด้วยฟิลด์ของตนเองเช่น contract_end_date, renewal_clause, blah blah blah สำหรับเอกสารที่ผู้ใช้กำหนดจะมีตารางเอกสารหลัก, ตาราง xcontract, เข้าร่วมในคีย์หลักทั่วไป (ดังนั้นคีย์หลักของ xcontracts ก็ต่างจากบนคีย์หลักของตารางหลัก) จากนั้นฉันจะสร้างมุมมองเพื่อตัดสองตารางนี้ ประสิทธิภาพเมื่อการสืบค้นรวดเร็ว นอกจากนี้ยังสามารถฝังกฎธุรกิจเพิ่มเติมลงในมุมมองได้ มันใช้งานได้ดีจริงๆสำหรับฉัน


1

ฐานข้อมูลของเราสนับสนุนแอพ SaaS (ซอฟต์แวร์ช่วยเหลือ) ที่ผู้ใช้มี "ฟิลด์กำหนดเอง" มากกว่า 7k เราใช้วิธีการรวม:

  1. (EntityID, FieldID, Value)ตารางสำหรับการค้นหาข้อมูล
  2. ฟิลด์ JSON ในentitiesตารางที่เก็บค่าเอนทิตีทั้งหมดที่ใช้สำหรับการแสดงข้อมูล (วิธีนี้คุณไม่จำเป็นต้องใช้ค่าเข้าร่วมนับล้านเพื่อรับค่าของค่า)

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

ป.ล. คู่ของคำเพื่อปกป้อง "Entity-Attribute-Value" วิธีการทุกคนยังคงทุบตี เราใช้หมายเลข # 1 โดยไม่ต้อง # 2 มานานหลายทศวรรษและใช้งานได้ดี บางครั้งมันเป็นการตัดสินใจทางธุรกิจ คุณมีเวลาที่จะเขียนแอพของคุณใหม่และออกแบบฐานข้อมูลใหม่หรือคุณสามารถโยน bucks สองสามตัวบนคลาวด์เซิร์ฟเวอร์ซึ่งราคาถูกจริงๆในสมัยนี้? โดยวิธีการเมื่อเราใช้ # 1 วิธีการฐานข้อมูลของเราถือหน่วยงานนับล้านเข้าถึงโดย 100s ของผู้ใช้นับพันและเซิร์ฟเวอร์ฐานข้อมูลแบบดูอัลคอร์ 16GB ทำได้ดี


สวัสดี @Alex ฉันเจอปัญหาที่คล้ายกัน ถ้าฉันเข้าใจดีคุณมี: 1) custom_fieldsตารางที่เก็บค่าเช่น 1 => last_concert_year, 2 => band, 3 => musicแล้วcustom_fields_valuesตารางที่มีค่า 001, 1, 1976 002, 1, 1977 003, 2, Iron Maiden003, 3 , Metal ความหวังเช่นทำให้รู้สึกกับคุณและขอโทษสำหรับการจัดรูปแบบ!
thitami

@thitami ไม่ถูกต้อง ตามตัวอย่างของคุณ: ฉันมีbandsตารางที่มีแถว1,'Iron Maiden'แล้วcustom_fieldsกับแถว1,'concert_year' | 2,'music'แล้วcustom_fields_valuesกับแถว1,1,'1977'|1,2,'metal'
อเล็กซ์

0

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

บางทีตัวเลือกอื่นคือการติดตามจำนวนของ UDF ที่สร้างโดยผู้ใช้แต่ละรายและบังคับให้ผู้ใช้นำฟิลด์เหล่านั้นกลับมาใช้ใหม่โดยบอกว่าพวกเขาสามารถใช้ฟิลด์กำหนดเอง 6 (หรือขีด จำกัด แบบสุ่มอื่น ๆ

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

ตอนนี้สิ่งที่ฉันจะทำคือตัวเลือก 4 (EDIT) ด้วยการเพิ่มลิงก์ไปยังผู้ใช้:

general_data_table
id
...


udfs_linked_table
id
general_data_id
udf_id


udfs_table
id
name
type
owner_id --> Use this to filter for the current user and limit their UDFs
string_link_id --> link table for string fields
int_link_id
type_link_id

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


0

ฉันจะแนะนำ# 4เนื่องจากระบบประเภทนี้ใช้ในMagentoซึ่งเป็นแพลตฟอร์ม CMS e-commerce ที่ได้รับการรับรองอย่างสูง ใช้ตารางเดียวเพื่อกำหนดฟิลด์ที่คุณกำหนดเองโดยใช้คอลัมน์fieldId & label จากนั้นให้แยกตารางสำหรับแต่ละชนิดข้อมูลและภายในแต่ละตารางเหล่านั้นจะมีดัชนีที่จัดทำดัชนีตามfieldIdและคอลัมน์ค่าของชนิดข้อมูล จากนั้นในแบบสอบถามของคุณให้ใช้สิ่งที่ชอบ:

SELECT *
FROM FieldValues_Text
WHERE fieldId IN (
    SELECT fieldId FROM Fields WHERE userId=@userId
)
AND value LIKE '%' + @search + '%'

สิ่งนี้จะทำให้มั่นใจได้ถึงประสิทธิภาพที่ดีที่สุดสำหรับประเภทที่ผู้ใช้กำหนดในความคิดเห็นของฉัน

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

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

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