การออกแบบฐานข้อมูล SQL ที่แนะนำสำหรับแท็กหรือการแท็ก [ปิด]


288

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

ฉันไม่มีแนวทางปฏิบัติที่ดีที่สุดสำหรับแท็กหรือไม่


9
ตกลงนี่คือคำถาม # 20856 คำถามเดียวกัน (เกือบ) คือ # 48475 ถามอย่างน้อยสองสัปดาห์หลังจากถามคำถามนี้
dlamblin

9
อีกคำถามที่น่าสนใจคือ "วิธีการใช้แท็ก?"
Mostafa

1
อีกคำถามที่น่าสนใจคือ "คุณจะทำให้พวกเขาเป็นสากลและถ้าเป็นเช่นนั้นได้อย่างไร"
DanMan

1
การเปรียบเทียบที่น่าสนใจ (เฉพาะ Postgres): databaseoup.com/2015/01/tag-all-things.html
a_horse_with_no_name

คำตอบ:


406

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

Table: Item
Columns: ItemID, Title, Content

Table: Tag
Columns: TagID, Title

Table: ItemTag
Columns: ItemID, TagID

32
นี่เป็นที่รู้จักกันในชื่อ“ โซลูชั่น Toxi” คุณสามารถค้นหาข้อมูลเพิ่มเติมได้ที่นี่: howto.philippkeller.com/2005/04/24/Tags-Database-schemas
นักพัฒนาพิกเซล

16
สิ่งหนึ่งที่ไม่ปรากฏในที่นี้คือ "แท็ก" หรือหมวดหมู่ในตารางแท็ก สิ่งนี้เป็นสิ่งจำเป็นสำหรับเว็บไซต์ที่มีหมวดหมู่และหมวดหมู่ย่อย ตัวอย่างเช่นไซต์สูตรอาหารไซต์ชิ้นส่วนอัตโนมัติไดเรกทอรีธุรกิจ ฯลฯ ข้อมูลประเภทนี้มักจะไม่จัดอยู่ในหมวดหมู่เดียวเพียงหมวดหมู่เดียวดังนั้นการติดแท็กคือคำตอบ แต่คุณจำเป็นต้องใช้บางอย่างเช่นชุดแบบซ้อนกันหรือโมเดลรายชื่อ Adjacency ในตารางแท็กของคุณ
HK1

5
ฉันเห็นด้วยกับ HK1 เป็นไปได้ด้วยโครงสร้างข้างต้น + ตาราง: คอลัมน์ TagGroup: TagGropuId, ตารางชื่อ: คอลัมน์แท็ก: TagID, ชื่อ, TagGroupId
Thunder

เมื่อฉันต้องการเพิ่มคอลัมน์ css ลงในตารางฉันจะเพิ่มคอลัมน์ css ลงในตารางแท็ก?
Amitābha

10
@ftvs: ลิงก์เสียหายอีกครั้งลิงก์ใหม่คือhowto.philippkeller.com/2005/04/24/Tags-Database-schemas
hansaplast

83

โดยปกติฉันจะเห็นด้วยกับยาคอฟเอลลิส แต่ในกรณีพิเศษนี้มีวิธีแก้ไขปัญหาอื่นที่ใช้งานได้:

ใช้สองตาราง:

Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID

Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title

นี่มีข้อดีที่สำคัญบางประการ:

ก่อนอื่นมันทำให้การพัฒนาง่ายขึ้นมาก: ในโซลูชันสามตารางสำหรับการแทรกและอัปเดตitemคุณต้องค้นหาTagตารางเพื่อดูว่ามีรายการอยู่แล้วหรือไม่ จากนั้นคุณต้องเข้าร่วมกับพวกเขาใหม่ นี่ไม่ใช่งานที่ไม่สำคัญ

จากนั้นทำให้ข้อความค้นหาง่ายขึ้น (และอาจเร็วกว่า) มีเคียวรีฐานข้อมูลหลักสามข้อที่คุณจะทำ: เอาท์พุททั้งหมดTagsสำหรับหนึ่งItem, วาด Tag-Cloud และเลือกรายการทั้งหมดสำหรับหนึ่งชื่อแท็ก

แท็กทั้งหมดสำหรับหนึ่งรายการ:

ตารางที่ 3:

SELECT Tag.Title 
  FROM Tag 
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 WHERE ItemTag.ItemID = :id

2 ตาราง:

SELECT Tag.Title
FROM Tag
WHERE Tag.ItemID = :id

แท็กเมฆ:

ตารางที่ 3:

SELECT Tag.Title, count(*)
  FROM Tag
  JOIN ItemTag ON Tag.TagID = ItemTag.TagID
 GROUP BY Tag.Title

2 ตาราง:

SELECT Tag.Title, count(*)
  FROM Tag
 GROUP BY Tag.Title

รายการสำหรับหนึ่งแท็ก:

ตารางที่ 3:

SELECT Item.*
  FROM Item
  JOIN ItemTag ON Item.ItemID = ItemTag.ItemID
  JOIN Tag ON ItemTag.TagID = Tag.TagID
 WHERE Tag.Title = :title

2 ตาราง:

SELECT Item.*
  FROM Item
  JOIN Tag ON Item.ItemID = Tag.ItemID
 WHERE Tag.Title = :title

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

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

อาร์กิวเมนต์ที่ไม่สอดคล้องกันก็เป็นสิ่งที่สงสัยเช่นกัน แท็กเป็นฟิลด์ข้อความอิสระและไม่มีการดำเนินการตามที่คาดไว้เช่น 'เปลี่ยนชื่อแท็กทั้งหมด "foo" เป็น "bar" "

tldr ดังนั้น: ฉันจะไปแก้ปัญหาสองตาราง (อันที่จริงฉันกำลังจะไปฉันพบบทความนี้เพื่อดูว่ามีข้อโต้แย้งที่ถูกต้องหรือไม่)


"Index: ItemId, Title" หมายถึงดัชนีสำหรับแต่ละดัชนีหนึ่งดัชนีหรือมีทั้งสองอย่าง
DanMan

ปกติสองดัชนี ขึ้นอยู่กับฐานข้อมูลที่คุณใช้
Scheintod

1
ในตารางแท็กคือ ItemId และแท็กคีย์ผสม? หรือคุณมี PK ด้วย?
Rippo

2
วิธีนี้คุณจะไม่สามารถสร้างแท็ก "ไม่ได้ใช้" เพื่อให้มีคุณสมบัติ "เพิ่มแท็ก" ในรายการ ในอีกวิธีหนึ่งคุณลักษณะ "เพิ่มแท็ก" สามารถดำเนินการได้อย่างอิสระ
Gianluca Ghettini

1
@Quilang ฉันยังเชื่อว่ามันขึ้นอยู่กับว่าคุณทำอะไรอยู่ :) ฉันใช้มันทั้งสองวิธีในโครงการต่าง ๆ ในครั้งสุดท้ายของฉันฉันลงเอยด้วยวิธีแก้ปัญหา 3 ตารางเพราะฉันต้องการ "แท็กประเภท" (หรือข้อมูลเมตาอื่น ๆ บนแท็ก) และสามารถนำโค้ดบางส่วนจากญาติที่ใกล้ชิดของแท็ก: พารามิเตอร์ แต่ในโครงการเดียวกันฉันใช้วิธีนี้เพื่อลูกพี่ลูกน้องที่ใกล้ยิ่งขึ้น: ค่าสถานะ (เช่น 'ขาย', 'ใหม่', 'ร้อน')
Scheintod

38

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

tagcloud: {
  map: function(doc){ 
    for(tag in doc.tags){ 
      emit(doc.tags[tag],1) 
    }
  }
  reduce: function(keys,values){
    return values.length
  }
}

การเรียกใช้สิ่งนี้ด้วย group = true จะจัดกลุ่มผลลัพธ์ตามชื่อแท็กและแม้แต่คืนค่าจำนวนครั้งที่พบแท็ก มันคล้ายกันมากกับการนับการเกิดขึ้นของคำในข้อความ


4
+1 ยินดีที่ได้เห็นการใช้งาน NoSQL บางอย่างเช่นกัน
Xeoncross

@NickRetallack ลิงก์ไม่ทำงาน หากทำได้โปรดอัปเดตคำตอบนี้
xralf

ตกลงฉันแทนที่ลิงค์ด้วยหนึ่งไปยัง archive.org
Nick Retallack

13

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

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

[1] RDBMS บางตัวจัดเตรียมประเภทอาร์เรย์เนทีฟซึ่งอาจเหมาะสมกว่าสำหรับการจัดเก็บโดยไม่ต้องใช้ขั้นตอนการแยกวิเคราะห์ แต่อาจทำให้เกิดปัญหากับการค้นหาข้อความแบบเต็ม


คุณทราบหรือไม่ว่าเครื่องมือค้นหาข้อความแบบเต็มที่ไม่พบความแตกต่างของคำ ตัวอย่างเช่นการค้นหาหนังสือจะส่งคืนหนังสือหรือไม่ นอกจากนี้คุณจะทำอย่างไรกับแท็กเช่น "c ++" ตัวอย่างเช่น SQL Server จะตัดเครื่องหมายบวกในดัชนี ขอบคุณ
โจนาธานวู้ด

ลองสฟิงซ์ - sphinxsearch.com
โรมัน

บทช่วยสอน 3 ส่วนนี้อาจมีประโยชน์สำหรับผู้ที่ไปเส้นทางนี้ (ค้นหาข้อความแบบเต็ม) มันใช้สิ่งอำนวยความสะดวกพื้นเมือง PostgreSQL: shisaa.jp/postset/postgresql-full-text-search-part-1.html
Will

นี้ดีกว่าคำตอบที่เลือกในแง่ของประสิทธิภาพหรือไม่

วิธีการเกี่ยวกับการจัดเก็บในการใช้ varchar 255, แท็กคั่นด้วยเครื่องหมายจุลภาคและเพิ่มดัชนีข้อความ kfull บนมัน?

9

ฉันเก็บแท็กไว้ในตารางแยกต่างหากเสมอจากนั้นก็มีตารางการแมป แน่นอนว่าฉันไม่เคยทำอะไรที่ใหญ่มากเช่นกัน

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


6
แม้นี้เป็นเรื่องง่ายมากขึ้นถ้าคุณไม่ได้ใช้ตารางการทำแผนที่ :)
Scheintod

0

ฉันอยากจะแนะนำการออกแบบต่อไปนี้: ตารางรายการ: Itemid, taglist1, taglist2
นี้จะรวดเร็วและทำให้ง่ายต่อการบันทึกและดึงข้อมูลที่ระดับรายการ

ในการสร้างแบบขนานตารางอื่น: แท็กแท็กไม่ได้ทำให้ตัวระบุแท็กที่ไม่ซ้ำกันและถ้าคุณใช้พื้นที่ในคอลัมน์ที่ 2 ซึ่งมี 100 รายการที่สร้างแถวอื่น

ตอนนี้ในขณะที่ค้นหารายการสำหรับแท็กมันจะเร็วสุด ๆ


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