วิธีการจัดเก็บรายการในคอลัมน์ของตารางฐานข้อมูล


117

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

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

มีทางออกที่ดีกว่านี้หรือไม่? หากมีคือไม่มีทางออกที่ดีกว่าแล้วทำไม? ดูเหมือนว่าปัญหานี้จะเกิดขึ้นเป็นครั้งคราว

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

ขอบคุณทุกคน!

จอห์น

อัปเดต: ดังนั้นในคำตอบแรกที่ฉันได้รับคำตอบฉันเห็นว่า "คุณสามารถไปเส้นทาง CSV / XML ได้ ... แต่อย่า!" ตอนนี้ฉันกำลังหาคำอธิบายว่าทำไม ชี้ให้ฉันดูข้อมูลอ้างอิงที่ดี

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

คำตอบ:


183

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

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

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

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

โดยทั่วไปกฎข้อแรก (หรือรูปแบบ) ของการทำให้เป็นมาตรฐานระบุว่าตารางของคุณต้องแสดงถึงความสัมพันธ์ ซึ่งหมายความว่า:

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

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

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


17
ดังนั้นคุณเชื่ออย่างยิ่งว่าการจัดเก็บรายการในคอลัมน์เป็นความคิดที่ไม่ดี แต่คุณไม่ได้ระบุสาเหตุ เนื่องจากฉันเพิ่งเริ่มต้นกับ SQL "ทำไม" สักเล็กน้อยจึงมีประโยชน์มาก ตัวอย่างเช่นคุณบอกว่าฉัน "ต่อสู้กับการต่อสู้ที่ยากลำบากและละเมิดหลักการพื้นฐานที่สุดข้อหนึ่งของการออกแบบฐานข้อมูลเชิงสัมพันธ์โดยไม่มีเหตุผลที่ดี" ... แล้วหลักการคืออะไร? เหตุใดจึงอ้างว่า "ไม่ดี" (โดยเฉพาะลักษณะการเรียงลำดับและอะตอมของรายการของฉัน)
JnBrymn

6
โดยพื้นฐานแล้วประสบการณ์หลายปีที่กลั่นกรองเป็นแนวทางปฏิบัติที่ดีที่สุด หลักพื้นฐานในคำถามเป็นที่รู้จักกันเป็นวันที่ 1 แบบปกติ
Toby

1
ขอบคุณอดัม ให้ข้อมูลมาก จุดที่ดีสำหรับคำถามสุดท้ายของคุณ
JnBrymn

8
“ […] และคุณจะไม่ถูกดูถูกโดยนักพัฒนา SQL คนอื่น ๆ เมื่อพวกเขาเห็นการออกแบบฐานข้อมูลของคุณ” มีเหตุผลที่ดีมากในการเคารพ First Normal Form (และคำตอบของคุณกล่าวถึงพวกเขา) แต่แรงกดดันจากเพื่อน /“ นั่นคือวิธีการทำสิ่งต่างๆที่นี่” ไม่ได้อยู่ในหมู่พวกเขา
Lynn

5
เราจัดเก็บรายการต่างๆไว้ในคอลัมน์ฐานข้อมูลทุกวันอยู่แล้ว เรียกว่า "ถ่าน" และ "varchar" แน่นอนใน Postgres พวกเขาเรียกอีกอย่างว่าข้อความ สิ่งที่ 1NF พูดจริงๆคือคุณไม่ควรต้องการแยกข้อมูลในฟิลด์ใด ๆ ออกเป็นฟิลด์เล็ก ๆ และถ้าคุณทำเช่นนั้นคุณก็โง่ ดังนั้นคุณจึงไม่จัดเก็บชื่อคุณเก็บชื่อส่วนบุคคลชื่อกลางและชื่อสกุล (ขึ้นอยู่กับการแปล) และรวมเข้าด้วยกัน มิฉะนั้นเราจะไม่จัดเก็บสตริงของข้อความเลย ในทางกลับกันสิ่งที่เขาต้องการคือสตริงของสตริง และมีวิธีการทำอย่างไร
Haakon Løtveit

15

คุณสามารถลืม SQL ไปด้วยกันและใช้แนวทาง "NoSQL" RavenDB , MongoDBและCouchDBเป็นวิธีแก้ปัญหาที่เป็นไปได้ ด้วยวิธีการ NoSQL คุณไม่ได้ใช้โมเดลเชิงสัมพันธ์.. คุณไม่ได้ถูก จำกัด ด้วยสกีมา


11

สิ่งที่ฉันเคยเห็นหลายคนทำคือสิ่งนี้ (อาจไม่ใช่แนวทางที่ดีที่สุดโปรดแก้ไขฉันถ้าฉันผิด):

ตารางที่ฉันใช้ในตัวอย่างแสดงไว้ด้านล่าง (ตารางนี้มีชื่อเล่นที่คุณตั้งให้กับแฟนสาวของคุณแฟนแต่ละคนมีรหัสเฉพาะ):

nicknames(id,seq_no,names)

สมมติว่าคุณต้องการจัดเก็บชื่อเล่นหลายชื่อภายใต้รหัส นี่คือเหตุผลที่เราได้รวมseq_noฟิลด์

ตอนนี้กรอกค่าเหล่านี้ลงในตารางของคุณ:

(1,1,'sweetheart'), (1,2,'pumpkin'), (2,1,'cutie'), (2,2,'cherry pie')

หากคุณต้องการค้นหาชื่อทั้งหมดที่คุณตั้งให้กับเพื่อนสาวของคุณ id 1 คุณสามารถใช้:

select names from nicknames where id = 1;

5

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

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

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

หากคุณต้องการวิธีที่ดีในการทำสิ่งนี้มักจะมีประเภทอาร์เรย์หรือคล้ายกัน ตัวอย่างเช่น Postgres เสนออาร์เรย์เป็นประเภทและให้คุณจัดเก็บอาร์เรย์ของข้อความหากนั่นคือสิ่งที่คุณต้องการและมีเทคนิคที่คล้ายกันสำหรับMySqlและMS SQLโดยใช้ JSON และDB2 ของ IBM ก็มีประเภทอาร์เรย์เช่นกัน (ในเอกสารที่เป็นประโยชน์ของตัวเอง) สิ่งนี้จะไม่ใช่เรื่องธรรมดาหากไม่มีความจำเป็นสำหรับสิ่งนี้

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


3

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

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


+1 สำหรับการคาดการณ์การเปลี่ยนแปลงในอนาคต - ออกแบบโมเดลข้อมูลของคุณให้ขยายได้เสมอ
coolgeek

2

ฉันแค่จัดเก็บเป็น CSV ถ้าเป็นค่าง่ายๆก็ควรเป็นสิ่งที่คุณต้องการ (XML เป็นแบบละเอียดมากและทำให้เป็นอนุกรมไปยัง / จากนั้นอาจจะมากเกินไป แต่ก็เป็นตัวเลือกเช่นกัน)

นี่คือคำตอบที่ดีสำหรับวิธีดึง CSV ออกด้วย LINQ


ฉันว่าเกี่ยวกับเรื่องนั้น ยังคงหมายความว่าฉันจะต้องทำให้เป็นอนุกรมและ deserialize ... แต่ฉันสงสัยว่ามันทำได้ ฉันต้องการมีบางให้อภัยวิธีที่จะทำสิ่งที่ฉันต้องการ แต่ฉันสงสัยว่ามีไม่ได้
JnBrymn

capnproto.orgเป็นวิธีที่ไม่ต้องทำให้เป็นซีเรียลไลซ์และดีซีเรียลไลซ์เร็วในทำนองเดียวกัน (เมื่อเทียบกับ csv หรือ xml) ในกรณีที่ capnproto ไม่ได้รับการสนับสนุนในภาษาที่คุณเลือกmsgpack.org/index.html
VoronoiPotato

2

หากคุณต้องการสอบถามในรายการให้เก็บไว้ในตาราง

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


1

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

นี่คือการออกแบบฐานข้อมูล 'ดั้งเดิม':

List(ListID, ListName) 
Item(ItemID,ItemName) 
List_Item(ListID, ItemID, SortOrder)

นี่คือตาราง de-normalized:

Lists(ListID, ListContent)

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


0

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


0

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


0

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

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

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

ALTER product ADD color varchar(80)

ในกรณีที่ความยาวของรายการของคุณแตกต่างกันคุณสามารถเติมช่องว่างภายในด้วย \ 0 ได้ตลอดเวลา

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

เหตุผลว่าทำไม: 1 / สะดวกมาก: ดึงรายการ i ที่สตริงย่อย i * n, (i +1) * n 2 / ไม่มีค่าใช้จ่ายในการสืบค้นข้ามตาราง 3 / มีประสิทธิภาพและประหยัดค่าใช้จ่ายมากขึ้นในฝั่งเซิร์ฟเวอร์ รายการเป็นเหมือนหยดเล็ก ๆ ที่ลูกค้าจะต้องแยก

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

"พระเจ้าห้ามมิให้ละเมิดหลักการอันศักดิ์สิทธิ์อันศักดิ์สิทธิ์ของ SQL": การใช้วิธีการที่เปิดกว้างและใช้ประโยชน์ได้มากขึ้นก่อนที่จะอ่านกฎนั้นเป็นหนทางที่จะไปได้เสมอ มิฉะนั้นคุณอาจจะกลายเป็นคนที่คลั่งไคล้ในการท่องThree Laws of Roboticsก่อนที่ Skynet จะถูกลบเลือนไป

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


แต่นี่เป็นกรณีที่เฉพาะเจาะจงมาก: จำนวนคงที่ของรายการที่มีความยาวคงที่ ถึงกระนั้นมันก็ทำให้การค้นหาง่ายๆเช่น "ผลิตภัณฑ์ทั้งหมดที่มีสีอย่างน้อย x" ยากกว่า SQL มาตรฐาน
Gert Arnold

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

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

0

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

เมื่อ Ed Codd กำลังพัฒนาแบบจำลองเชิงสัมพันธ์ในปี 1969-1970 เขาได้กำหนดรูปแบบปกติที่ไม่อนุญาตให้มีการซ้อนตารางแบบนี้ รูปแบบปกติต่อมาเรียกว่ารูปแบบปกติแรก จากนั้นเขาก็แสดงให้เห็นว่าสำหรับทุกฐานข้อมูลมีฐานข้อมูลในรูปแบบปกติแรกที่แสดงข้อมูลเดียวกัน

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

หากคุณอนุญาตให้เซลล์มีรายการหรือตารางหรือคอลเลกชันอื่น ๆ ตอนนี้คุณไม่สามารถให้การเข้าถึงแบบคีย์ไปยังรายการย่อยโดยไม่ต้องใช้แนวคิดของคีย์ซ้ำ

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


-1

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

ฐานข้อมูล:

 _____________________
|  word  | letters    |
|   me   | '[m, e]'   |
|  you   |'[y, o, u]' |  note that the letters column is of type 'TEXT'
|  for   |'[f, o, r]' |
|___in___|_'[i, n]'___|

และฟังก์ชันลิสต์คอมไพเลอร์ (เขียนด้วยภาษาไพ ธ อน แต่ควรแปลเป็นภาษาโปรแกรมอื่น ๆ ได้ง่ายที่สุด) TEXT แสดงถึงข้อความที่โหลดจากตาราง sql ส่งคืนรายการสตริงจากสตริงที่มีรายการ หากคุณต้องการให้ส่งคืน ints แทนสตริงให้สร้างโหมดเท่ากับ 'int' เช่นเดียวกันกับ "string" "bool" หรือ "float"

def string_to_list(string, mode):
    items = []
    item = ""
    itemExpected = True
    for char in string[1:]:
        if itemExpected and char not in [']', ',', '[']:
            item += char
        elif char in [',', '[', ']']:
            itemExpected = True
            items.append(item)
            item = ""
    newItems = []
    if mode == "int":
        for i in items:
            newItems.append(int(i))

    elif mode == "float":
        for i in items:
            newItems.append(float(i))

    elif mode == "boolean":
        for i in items:
            if i in ["true", "True"]:
                newItems.append(True)
            elif i in ["false", "False"]:
                newItems.append(False)
            else:
                newItems.append(None)
    elif mode == "string":
        return items
    else:
        raise Exception("the 'mode'/second parameter of string_to_list() must be one of: 'int', 'string', 'bool', or 'float'")
    return newItems

นอกจากนี้ยังมีฟังก์ชัน list-to-string ในกรณีที่คุณต้องการ

def list_to_string(lst):
    string = "["
    for i in lst:
        string += str(i) + ","
    if string[-1] == ',':
        string = string[:-1] + "]"
    else:
        string += "]"
    return string
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.