태그 또는 태그 지정을위한 권장 SQL 데이터베이스 디자인 [닫기]


288

태그를 구현하는 몇 가지 방법에 대해 들었습니다. TagID와 ItemID 사이의 매핑 테이블을 사용하면 (나에게 이해가되지만 확장 가능합니까?) 고정 가능한 수의 TagID 열을 ItemID에 추가 (나쁜 생각처럼 보임), 쉼표로 구분 된 텍스트 열에 태그 유지 (소리) 미친하지만 작동 할 수 있습니다). 누군가 희소 행렬을 추천한다고 들었지만 태그 이름이 어떻게 우아하게 커 집니까?

태그에 대한 모범 사례가 누락 되었습니까?


9
자, 이것은 질문 # 20856입니다. (거의) 같은 질문은 # 48475이 질문을받은 후 적어도 2 주 후에 질문했습니다.
dlamblin

9
또 다른 흥미로운 질문은 "SO가 어떻게 태그를 구현합니까?"입니다.
Mostafa

1
또 다른 흥미로운 질문은 "그들을 국제화하겠습니까? 그렇다면 어떻게 하시겠습니까?"입니다.
DanMan

1
흥미로운 비교 (Postgres 특정) : databasesoup.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
The Pixel Developer

16
여기에 표시되지 않은 것은 태그 테이블의 계층 구조 "태그"또는 범주입니다. 이것은 카테고리와 하위 카테고리가 있지만 태그의 유연성이 필요한 사이트에서 일반적으로 필요합니다. 예를 들어 레시피 사이트, 자동차 부품 사이트, 비즈니스 디렉토리 등 이러한 유형의 데이터는 일반적으로 하나의 단일 범주에만 적합하지 않으므로 태그 지정이 정답이지만 중첩 세트 모델 또는 인접 목록 모델과 같은 것을 사용해야합니다. 태그 테이블에
홍콩

5
HK1을 사용하여 위의 구조 + 테이블 : TagGroup 열 : TagGropuId, 제목 테이블 : Tag 열 : TagID, Title, TagGroupId
Thunder

css 열을 테이블에 추가하고 싶을 때 css 열을 태그 테이블에 추가합니까?
Amitābha

10
@ftvs : 링크가 다시 끊어짐, 새 링크는 howto.philippkeller.com/2005/04/24/Tags-Database-schemas
hansaplast

83

일반적으로 Yaakov Ellis에 동의하지만이 특별한 경우에는 다른 가능한 해결책이 있습니다.

두 개의 테이블을 사용하십시오.

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

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

여기에는 몇 가지 주요 장점이 있습니다.

먼저 삽입과 업데이트를위한 3 테이블 솔루션에서 이미 항목이 있는지 확인하기 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 : 나는 두 테이블 솔루션을 갈 것입니다. (사실 것입니다.이 기사에서 이에 대한 유효한 논증이 있는지 확인했습니다.)


"색인 : ItemId, 제목"은 각각 또는 하나를 포함하는 하나의 색인을 의미합니까?
DanMan

일반적으로 두 개의 인덱스. 그래도 사용중인 데이터베이스에 따라 다를 수 있습니다.
Scheintod

1
태그 테이블에는 ItemId가 있고 복합 키에는 태그가 있습니까? 또는 PK도 있습니까?
Rippo

2
이렇게하면 "사용하지 않은"태그를 만들 수 없으므로 항목에 대해 "태그 추가"기능을 수행해야합니다. 다른 방법으로는 "태그 추가"기능을 독립적으로 수행 할 수 있습니다.
Gianluca Ghettini

1
@Quilang. 나는 여전히 그것이 당신이 무엇인지에 달려 있다고 믿는다 :) 나는 다른 프로젝트에서 두 가지 방법으로 그것을 구현했다. 마지막으로 "태그 유형"(또는 태그에 대한 다른 메타 정보)이 필요하고 태그의 가까운 사촌에서 일부 코드를 다시 사용할 수 있기 때문에 3 테이블 솔루션으로 끝났습니다. 그러나 매우 동일한 프로젝트에서 나는 훨씬 더 가까운 사촌을 위해이 방법을 정확하게 사용했다 : 플래그 (예 : '판매', '신규', '핫')
Scheintod

38

couchdb와 같이 map-reduce를 지원하는 데이터베이스를 사용하는 경우 일반 텍스트 필드 또는 목록 필드에 태그를 저장하는 것이 가장 좋습니다. 예:

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

group = true로 이것을 실행하면 태그 이름별로 결과를 그룹화하고 태그가 발생한 횟수를 반환합니다. text에서 단어의 발생 횟수계산하는 것과 매우 유사 합니다 .


4
+1 NoSQL 구현도 만나서 반가워요.
Xeoncross

@NickRetallack 링크가 작동하지 않습니다. 가능하면이 답변을 업데이트하십시오.
xralf

Ok. 링크를 archive.org로 교체했습니다.
Nick Retallack

13

태그를 저장하는 데 단일 형식의 텍스트 열 [1]을 사용하고이를 가능하게하는 전체 텍스트 검색 엔진을 사용하십시오. 그렇지 않으면 부울 쿼리를 구현하려고 할 때 스케일링 문제가 발생합니다.

보유한 태그에 대한 세부 사항이 필요한 경우 점진적으로 유지 보수 된 테이블에서 태그를 추적하거나 배치 작업을 실행하여 정보를 추출 할 수 있습니다.

[1] 일부 RDBMS는 구문 분석 단계를 필요로하지 않아도 저장에 더 적합한 기본 배열 유형을 제공하지만 전체 텍스트 검색에 문제를 일으킬 수 있습니다.


단어에서 변형을 찾지 못하는 전체 텍스트 검색 엔진에 대해 알고 있습니까? 예를 들어 책을 검색하면 책이 반환됩니까? 또한 "c ++"와 같은 태그에 대해서는 어떻게합니까? 예를 들어 SQL Server는 인덱스에서 더하기 부호를 제거합니다. 감사.
Jonathan Wood

스핑크스 -sphinxsearch.com
Roman

이 3 부 자습서는이 경로를 찾는 사람들에게 유용 할 수 있습니다 (전체 텍스트 검색). PostgreSQL 기본 기능을 사용하고 있습니다 : shisaa.jp/postset/postgresql-full-text-search-part-1.html
Will

성능 측면에서 선택한 답변보다 낫습니까?

varchar 255, 쉼표로 구분 된 태그를 사용하여 저장하고 kfull text index를 추가하는 방법은 무엇입니까?

9

나는 항상 태그를 별도의 테이블에 보관 한 다음 매핑 테이블을 가졌습니다. 물론 나는 정말 큰 규모로 아무것도 한 적이 없습니다.

"태그"테이블과 맵 테이블을 사용하면 태그 클라우드를 생성하기가 쉽지 않습니다. SQL을 쉽게 결합하여 각 태그가 얼마나 자주 사용되는지에 대한 수를 가진 태그 목록을 얻을 수 있기 때문입니다.


6
만약 당신이 매핑 테이블을 사용하지 않으면 더욱 쉬워집니다 :)
Scheintod

0

다음 디자인을 제안합니다. Item Table : Itemid, taglist1, taglist2
빠르고 빠르며 항목 수준에서 데이터를 쉽게 저장하고 검색 할 수 있습니다.

병렬로 다른 테이블 만들기 : 태그 태그는 태그를 고유 식별자로 만들지 않으며 두 번째 열의 공간이 부족하면 100 개의 항목이 다른 행을 만들 수 있습니다.

이제 태그 항목을 검색하는 동안 매우 빠릅니다.


en.wikipedia.org/wiki/First_normal_form 이것에 예외가 있지만 비정규화할 수 있지만 여기서는 불가능합니다
Dheeraj
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.