태그 또는 태깅을 위한 권장 SQL 데이터베이스 디자인 [닫기]
-
09-06-2019 - |
문제
태그 지정을 구현하는 몇 가지 방법에 대해 들었습니다.TagID와 ItemID 사이의 매핑 테이블 사용(나에게는 이해가 되지만 확장 가능합니까?), ItemID에 고정된 수의 가능한 TagID 열 추가(나쁜 생각인 것 같습니다), 쉼표로 구분된 텍스트 열에 태그 유지(소리 미쳤지 만 작동 할 수 있습니다).누군가 희소 행렬을 추천한다는 이야기도 들었습니다. 그런데 태그 이름이 어떻게 우아하게 커지나요?
태그에 대한 모범 사례가 누락되었나요?
해결책
적절하게 인덱싱되고 적절한 데이터베이스에서 실행되는 외래 키가 있는 세 개의 테이블(하나는 모든 항목 저장용, 하나는 모든 태그용, 하나는 둘 사이의 관계용)이 제대로 작동하고 적절하게 확장되어야 합니다.
Table: Item
Columns: ItemID, Title, Content
Table: Tag
Columns: TagID, Title
Table: ItemTag
Columns: ItemID, TagID
다른 팁
일반적으로 나는 Yaakov Ellis의 의견에 동의하지만 이 특별한 경우에는 또 다른 실행 가능한 솔루션이 있습니다.
두 개의 테이블을 사용하십시오.
Table: Item
Columns: ItemID, Title, Content
Indexes: ItemID
Table: Tag
Columns: ItemID, Title
Indexes: ItemId, Title
여기에는 몇 가지 주요 이점이 있습니다.
먼저 개발이 훨씬 간단해집니다.삽입 및 업데이트를 위한 3테이블 솔루션 item
당신은 검색해야 Tag
테이블에 이미 항목이 있는지 확인하세요.그런 다음 새로운 것과 합류해야합니다.이것은 결코 사소한 일이 아닙니다.
그러면 쿼리가 더 간단해지고 빨라질 수도 있습니다.수행할 세 가지 주요 데이터베이스 쿼리는 다음과 같습니다.모두 출력 Tags
하나를 위해 Item
, 태그 클라우드를 그리고 하나의 태그 제목에 대한 모든 항목을 선택합니다.
하나의 항목에 대한 모든 태그:
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 :나는 2 테이블 솔루션을 선택하겠습니다.(사실 갈 예정이에요.이에 반대하는 타당한 주장이 있는지 확인하기 위해 이 기사를 찾았습니다.)
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로 실행하면 결과가 태그 이름별로 그룹화되고 태그가 발생한 횟수도 반환됩니다.그것은 매우 유사하다 텍스트에서 단어의 발생 횟수 세기.
태그를 저장하기 위해 단일 형식의 텍스트 열[1]을 사용하고 이를 색인화하기 위해 가능한 전체 텍스트 검색 엔진을 사용합니다.그렇지 않으면 부울 쿼리를 구현하려고 할 때 크기 조정 문제가 발생합니다.
보유하고 있는 태그에 대한 세부 정보가 필요한 경우 증분적으로 유지 관리되는 테이블에서 이를 추적하거나 일괄 작업을 실행하여 정보를 추출할 수 있습니다.
[1] 일부 RDBMS는 구문 분석 단계가 필요하지 않아 저장에 더 적합할 수 있지만 전체 텍스트 검색에 문제를 일으킬 수 있는 기본 배열 유형을 제공하기도 합니다.
저는 항상 태그를 별도의 테이블에 보관하고 매핑 테이블을 사용했습니다.물론 나도 정말 큰 규모로 어떤 일을 해본 적이 없다.
"태그" 테이블과 맵 테이블이 있으면 태그 클라우드를 생성하는 것이 매우 간단해집니다. SQL을 쉽게 결합하여 각 태그가 사용되는 빈도를 계산한 태그 목록을 얻을 수 있기 때문입니다.
나는 다음과 같은 디자인을 제안합니다 :품목 테이블:항목 ID, 태그 목록1, 태그 목록2
이는 속도가 빠르고 항목 수준에서 데이터를 쉽게 저장하고 검색할 수 있게 해줍니다.
병렬로 다른 테이블을 빌드합니다.태그 태그는 태그 고유 식별자를 만들지 않으며 두 번째 열에서 공간이 부족한 경우 100 개 항목이 다른 행을 생성한다고 가정합니다.
이제 태그에 대한 항목을 검색하는 것이 매우 빨라질 것입니다.