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


11

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

"จะมีสถานการณ์สมมติที่จัดเก็บข้อมูลในบรรทัด (สตริง) แทนที่จะแสดงหลายบรรทัดหรือไม่"

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

ที่นั่นเราจะมีสองคอลัมน์ หนึ่งเรียกว่าCountryและอื่น ๆ Statesที่เรียกว่า ตามที่กล่าวไว้ที่นี่และที่เสนอโดยของ @ srutzky คำตอบที่PKจะได้รับรหัสที่กำหนดโดยมาตรฐาน ISO 3166-1 alpha-3

ตารางของเราจะเป็นดังนี้:

+---------+-----------------------+-------------------------------------------------------+
| Country | States                | StateName                                             |
+---------+-----------------------+-------------------------------------------------------+
| USA     | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+

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

เราสรุปว่าแบบจำลองนี้ไม่มีประโยชน์มาก แต่ฉันสงสัยว่าอาจมีวิธีทำให้มีประโยชน์

สิ่งที่ผมอยากจะถามคือถ้าใด ๆ ของคุณได้เห็นได้ยินหรือสิ่งที่ทำเช่นนี้ในทางที่มันทำงาน


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

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

สถานการณ์ที่เป็นไปได้คือการเก็บตัวแปร ร้านa;b;cใช้ปลายด้านหน้าที่จะแยกสายของคุณแล้วคุณจะได้รับa, b, cและดำเนินการเกี่ยวกับการดำเนินการทำอะไรบางอย่างกับพวกเขาอาจจะ ?. รู้สึกว่ามันอาจเหมาะกับความต้องการเฉพาะในแบบนั้น ... ในความคิดที่สองไม่มี คุณสามารถจัดเก็บ ID เข้าร่วมตารางของคุณและสร้างสตริงที่ต่อกันได้มากกว่าที่จะสามารถส่งเนื้อหาไปยัง FE ...
Nelz

เพื่อความเป็นธรรม (กับผมอย่างน้อย ;-) ผมเสนอใช้2 ตัวอักษรรหัสประเทศ :-) ในที่อื่น ๆคำตอบ
โซโลมอน Rutzky

2
โปรดสังเกตว่าไม่มีใครมีคุณสมบัติเกี่ยวกับการจัดเก็บค่า "Alabama" ในคอลัมน์แทนที่จะมีตารางแยกต่างหากพร้อมคอลัมน์ STATE, N & C สำหรับ "สถานะของรัฐ STATE มีอักขระ Nth C" เพราะ 1. เราไม่ต้องการสอบถามเกี่ยวกับตัวอักษรของชื่อหรือ 2. เราไม่สนใจการเรียกใช้ฟังก์ชัน NTH_CHAR (N, S) ที่ส่งคืน "อักขระ Nth ของสตริง S" ในทุกแถวที่มีชื่อถ้าเราทำ . (Vs JOIN & ตัวดำเนินการสัมพันธ์อื่น ๆ กำจัดบางแถวเช่นนี้ผ่านตารางเสริม) Ditto สำหรับจำนวนเต็มและ NTH_DIGIT (N, I) มันมักจะเรียกการตัดสินว่าสิ่งที่อยู่ในฐานข้อมูลเฉพาะคืออะตอมสัมพันธ์
philipxy

คำตอบ:


13

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

คำเดียว: ไม่ถ้าคุณกำลังเก็บจุดข้อมูลจริงมันจะทำให้เกิดความเจ็บปวดเท่านั้น (ในแง่ของรหัสและประสิทธิภาพ) เนื่องจากเป็นภาวะแทรกซ้อนที่ไม่จำเป็น หากเป็นค่าที่จะถูกจัดเก็บเป็นหน่วยเดียวอัพเดตเป็นหน่วยเดียวและไม่แยกชิ้นส่วนภายในฐานข้อมูลนั่นอาจเป็นเรื่องปกติเนื่องจากมีความคล้ายคลึงกับการจัดเก็บภาพหรือ PDF มิฉะนั้นความพยายามในการแยกวิเคราะห์ข้อมูลจะทำให้การใช้ดัชนีใด ๆ (เช่นการใช้LIKE '%something%'หรือCHARINDEXหรือPATINDEXหรือหรือSUBSTRINGฯลฯ )

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

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

นอกจากนี้เมื่อกำหนดสถานการณ์เช่นสิ่งที่แสดงในคำถามข้างต้นโดยการเชื่อม StateCodes ทั้งหมดเข้าด้วยกันคุณจะไม่สามารถรับ Foreign Key (ในทิศทางใดทางหนึ่ง) ค่าเหล่านั้น

และถ้าความต้องการทางธุรกิจเปลี่ยนแปลงไปตามกาลเวลาและคุณต้องติดตามคุณสมบัติเพิ่มเติมของรายการเหล่านี้ ในแง่ของ "รัฐ" สิ่งที่เกี่ยวกับเมืองหลวงหรือประชากรหรือการเรียงลำดับหรือสิ่งอื่นใด จัดเก็บอย่างเหมาะสมเหมือนแถวคุณสามารถเพิ่มคอลัมน์เพิ่มเติมสำหรับคุณสมบัติเพิ่มเติม แน่นอนว่าคุณสามารถมีข้อมูลแยกวิเคราะห์ได้หลายระดับเช่น|StateCode,Capital,Population |StateCode,Capital,Populate|...แต่หวังว่าทุกคนจะเห็นปัญหาที่เพิ่มขึ้นอย่างไม่สามารถควบคุมได้ แน่นอนว่าปัญหานี้ค่อนข้างจะจัดการได้อย่างง่ายดายกับรูปแบบ XML และ JSON และนั่นคือค่าของพวกเขาดังกล่าวข้างต้น แต่คุณจะยังคงต้องการเหตุผลที่ดีมากสำหรับการใช้แบบจำลองเหล่านั้นเป็นวิธีเริ่มต้นในการสร้างแบบจำลองซึ่งไม่ได้มีประสิทธิภาพเท่าการใช้ฟิลด์แบบแยกในแถวที่แยก


9

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

OutputType   OutputHeader
PersonalData Name|Address|City|State|Zip
JobInfo      Name|JobName|JobTitle

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

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


1

ฉันใช้มันครั้งเดียวกับโต๊ะเล็ก ๆ เช่น:

CREATE TABLE t1 (
  ID number,
  some_feature   varchar2(100),
  valid_channels  varchar2(100));

CREATE TABLE channel_def (
  channel varchar2(100));

แล้วเก็บค่าเข้าCRM,SMS,SELF-CAREvalid_channel

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

แต่โดยทั่วไปฉันหลีกเลี่ยงมันไม่ใช่ 3NF

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

SELECT * 
  FROM t1 
 INNER JOIN channel_def cd
    ON ','||t1.valid_channels||',' LIKE '%,'||cd.channel||',%';

+ น่ากลัวใน Oracle '%,'ปิดการใช้งานการใช้ดัชนีเพราะของการเริ่มต้น


ข้อใดจะช้ากว่า: LIKEหรือการเข้าร่วมแบบง่าย
Human_After ทั้งหมด

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

@Human_AfterAll LIKEจะช้าลงโดยเฉพาะอย่างยิ่งถ้าข้อมูลเป็นแบบจำลองอย่างถูกต้องเพื่อจะใช้ข้อมูลในTINYINT PK channel_defจากนั้นจะต้องเปรียบเทียบไบต์เดียวระหว่างสองตาราง ที่นี่ก็มีการแยกสตริงตัวอักษรโดยตัวอักษร (อย่างน้อยก็จนกว่าเงื่อนไขที่มีความพึงพอใจ) และจะทำการค้นหากรณีตาย (ยึดตามตารางที่กำหนด def ไม่ได้แสดง_BIN2การเปรียบเทียบการใช้งาน) สิ่งนี้จะทำให้ดัชนีใน SQL Server เป็นโมฆะเช่นกัน ฉันพูดถึงเรื่องนี้ในคำตอบโดยบอกว่าการแยกวิเคราะห์ไม่สามารถใช้ดัชนีได้ ฉันเพิ่งปรับปรุงคำตอบเพื่อให้ชัดเจนยิ่งขึ้น
โซโลมอน Rutzky

1
@ Human_After ทั้งหมดฉันจะบอกว่าการตัดสินใจสร้างแบบจำลองนี้เกิดขึ้นจากการขาดประสบการณ์และความรู้ (และบางครั้งความขี้เกียจ) เข้าร่วมเพิ่มเติมอีกอย่างหนึ่งคือทั้งหมดที่ถูกบันทึกไว้ แต่สิ่งที่เสียสละคือความสามารถในการ Foreign Key ซึ่งจะป้องกันไม่ให้ข้อมูลปลอมทั้งหมดเข้ามา (แม้ว่าจะไม่ตรงกับLIKEข้อและสร้างผลลัพธ์แปลก ๆ ก็ยังสามารถทำให้เกิดปัญหาอื่น ๆ หรือ อย่างน้อยทำการแก้จุดบกพร่องหนัก / อีกต่อไป) นอกจากนี้ยังทำให้การอัปเดตvalid_channelsฟิลด์มีความซับซ้อนมากขึ้น นี่ไม่ได้เป็นการบอกว่ามันใช้ไม่ได้ไม่มีเหตุผลที่ดีที่จะทำมัน
โซโลมอน Rutzky

"ขาดประสบการณ์" - สิ่งที่เลวร้ายที่สุดคือการตัดสินใจการออกแบบนี้โดยเฉพาะได้รับการกำหนดโดยเจ้าหน้าที่อาวุโส ...
Robotron

1

สิ่งนี้ทำที่ SE ตามที่ Marc Gravell เขียน :

... หลังจากคิดและไตร่ตรองเราได้ตัดสินจากการเป็นตัวแทนตามธรรมชาติของแถบ (บาร์) ที่มีการนำหน้า / ต่อท้ายดังนั้น“ .net c #” จึงกลายเป็นเพียง“ | .net | c # |” สิ่งนี้มีคุณธรรม:

  • ง่ายมากที่จะแยกวิเคราะห์
  • การอัปเดตและการลบแท็กจำนวนมากสามารถทำได้ด้วยการแทนที่อย่างง่าย (รวมถึงไพพ์เพื่อหลีกเลี่ยงการแทนที่การจับคู่แท็กกลาง)
  • ...

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

พวกเขาไม่ได้ทำให้สิ่งต่าง ๆ เป็นปกติอย่างสมบูรณ์ทั้งปริมาณงานและเหตุผลด้านประสิทธิภาพ


0

ประโยชน์หลักอย่างหนึ่งที่เป็นไปได้ของการใช้สตริงและชนิดข้อมูลอื่นคือส่งจาก SQL Server ไปยัง C #, C, C ++ (ฯลฯ ) โดยใช้ SQLCLR เมื่อต้องการประสิทธิภาพที่แท้จริง คุณสามารถสร้างมุมมองหรือกระบวนงานที่เก็บไว้เพื่อแสดงข้อมูลเชิงสัมพันธ์ที่ไม่ใช่แบบสัมพันธ์เช่นคุณมีตัวอย่างของคุณด้านบนเพื่อจุดประสงค์นี้

ดูตัวอย่างนี้:

http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/

ต่อ Wikipedia: SQL CLR หรือ SQLCLR (SQL Common Language Runtime) เป็นเทคโนโลยีสำหรับการโฮสต์ของ Microsoft .NET Runtime Language ธรรมดาภายใน SQL Server SQLCLR อนุญาตให้โค้ดที่จัดการถูกโฮสต์โดยและรันในสภาพแวดล้อม Microsoft SQL Server


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

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

0

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

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

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

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