태그 지정을 위한 데이터베이스 설계
다음 태그 지정 기능을 지원하도록 데이터베이스를 설계하는 방법은 무엇입니까?
- 항목에 많은 태그가 있을 수 있습니다.
- 지정된 태그 집합으로 태그가 지정된 모든 항목에 대한 검색은 신속해야 합니다(항목에 모든 태그가 있어야 하므로 OR 검색이 아닌 AND 검색임).
- 빠른 조회/읽기를 사용하기 위해 항목 생성/쓰기 속도가 느릴 수 있습니다.
n개 이상의 지정된 태그 집합으로 태그가 지정된 모든 항목의 조회는 단일 SQL 문을 사용하여 수행하는 것이 이상적입니다.검색할 태그 수와 항목의 태그 수를 알 수 없고 높을 수 있으므로 JOIN을 사용하는 것은 비현실적입니다.
아이디어 있어요?
지금까지 답변해 주셔서 감사합니다.
하지만 제가 틀리지 않았다면, 주어진 답은 태그에 대한 OR 검색을 수행하는 방법을 보여줍니다.n개 이상의 태그가 있는 모든 항목을 선택합니다.저는 효율적인 AND 검색을 찾고 있습니다. (모든 n개 태그가 있는 모든 항목을 선택하십시오. 그리고 그 이상일 수도 있습니다.)
다음은 데이터베이스 스키마 태그 지정에 대한 좋은 기사입니다.
http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/
성능 테스트와 함께:
http://howto.philippkeller.com/2005/06/19/Tagsystems-performance-tests/
결론은 MySQL에 매우 구체적이며(적어도 작성 당시 2005년에는) 전체 텍스트 인덱싱 특성이 매우 좋지 않았습니다.
ANDing 정보:"관계적 분할" 작업을 찾고 있는 것처럼 들립니다.이 기사는 간결하면서도 이해할 수 있는 방식으로 관계 분할을 다룹니다.
성능에 대해: 비트맵 기반의 접근 방식은 직관적으로 상황에 잘 맞는 것처럼 들립니다.하지만 digiguru가 제안하는 것처럼 비트맵 인덱싱을 수동으로 구현하는 것이 좋은 생각이라고 확신하지 않습니다.새 태그가 추가될 때마다 복잡한 상황처럼 들립니다(?). 그러나 일부 DBMS(오라클 포함)는 인덱스 유지 관리의 잠재적 복잡성을 제거하는 내장 인덱싱 시스템 때문에 어떻게든 사용할 수 있는 비트맵 인덱스를 제공합니다.비트맵 인덱스를 제공하는 DBMS는 쿼리 계획을 수행할 때 적절한 인덱스를 고려할 수 있어야 합니다.
저는 @Jeff Atwood가 링크하는 (http://howto.philippkeller.com/2005/04/24/Tags-Database-schemas/) ) 기사가 매우 철저하고(3가지 스키마 접근법의 장점을 논의함), 일반적으로 지금까지 언급된 것보다 더 잘 수행될 AND 쿼리에 대한 좋은 솔루션을 가지고 있다는 것을 강조하고 싶습니다(즉, 각 용어에 대해 상관된 하위 쿼리를 사용하지 않음).그리고 댓글에 좋은 것들도 많이 있습니다.
ps - 여기서 모두가 이야기하는 접근법을 기사에서 "Toxi" 솔루션이라고 합니다.
간단한 해결책에는 문제가 없다고 생각합니다.항목 테이블, 태그 테이블, "태그" 크로스 테이블
크로스 테이블의 인덱스는 충분히 최적화되어야 합니다.적절한 항목을 선택하는 것은
SELECT * FROM items WHERE id IN
(SELECT DISTINCT item_id FROM item_tag WHERE
tag_id = tag1 OR tag_id = tag2 OR ...)
그리고 태깅은
SELECT * FROM items WHERE
EXISTS (SELECT 1 FROM item_tag WHERE id = item_id AND tag_id = tag1)
AND EXISTS (SELECT 1 FROM item_tag WHERE id = item_id AND tag_id = tag2)
AND ...
많은 수의 비교 태그에 대해서는 분명히 그렇게 효율적이지 않습니다.태그 수를 메모리에 유지하려면 자주 사용하지 않는 태그로 시작하도록 쿼리할 수 있으므로 AND 시퀀스를 더 빨리 평가할 수 있습니다.일치할 것으로 예상되는 태그의 수와 일치할 것으로 예상되는 태그의 수에 따라 20개의 태그를 일치시키고 임의의 항목이 15개의 태그와 일치할 것으로 예상되는 경우 이는 여전히 데이터베이스에서 무거운 해결책일 수 있습니다.
Java Content Repository 구현(예: Apache Jackrabbit)과 같은 엄격하지 않은 데이터베이스 솔루션으로 실험하고 Apache Lucene과 같은 솔루션 위에 구축된 검색 엔진을 사용할 수 있습니다.
적절한 캐싱 메커니즘을 갖춘 이 솔루션은 자체 개발 솔루션보다 더 나은 성능을 제공할 수 있습니다.
그러나 중소 규모의 애플리케이션에서는 이전 게시물에서 언급한 표준화된 데이터베이스보다 더 정교한 구현이 필요하다고 생각하지 않습니다.
편집: JCR과 같은 솔루션을 검색 엔진과 함께 사용하는 것이 더 설득력 있어 보입니다.그것은 장기적으로 당신의 프로그램을 크게 단순화시킬 것입니다.
가장 쉬운 방법은 태그 테이블을 만드는 것입니다.
Target_Type
를 지정하는 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
Target
태그가 지정된 레코드의 키
Tag
태그의 텍스트
데이터 쿼리는 다음과 같습니다.
Select distinct target from tags
where tag in ([your list of tags to search for here])
and target_type = [the table you're searching]
갱신하다
AND에 대한 당신의 요구 조건에 따라, 위의 쿼리는 다음과 같은 것으로 바뀔 것입니다.
select target
from (
select target, count(*) cnt
from tags
where tag in ([your list of tags to search for here])
and target_type = [the table you're searching]
)
where cnt = [number of tags being searched]
저는 @Zizzencs 제안을 두 번째로 하고 싶습니다. 당신은 완전히 (R)DB 중심적이지 않은 것을 원할 수도 있습니다.
어떻게든 일반 nvarchar 필드를 사용하여 적절한 캐싱/인덱스를 사용하여 태그를 저장하면 더 빠른 결과를 얻을 수 있다고 생각합니다.하지만 그건 그저 저입니다.
저는 이전에 다대다 관계(Item Tags ItemTags)를 나타내기 위해 3개의 테이블을 사용하는 태그 시스템을 구현한 적이 있지만, 여러분이 많은 곳에서 태그를 다룰 것이라고 생각합니다. 항상 3개의 테이블을 동시에 조작/쿼리해야 하기 때문에 분명히 코드가 더 복잡해질 것입니다.
추가된 복잡성이 그럴 가치가 있는지 고려해 보는 것이 좋습니다.
조인을 피할 수는 없지만 그래도 어느 정도 정상화됩니다.
제 접근 방식은 태그 테이블을 갖는 것입니다.
TagId (PK)| TagName (Indexed)
그러면 항목 표에 TagXREFID 열이 표시됩니다.
이 TagXREFID 열은 세 번째 테이블에 대한 FK입니다. TagXREF:
TagXrefID | ItemID | TagId
따라서 항목에 대한 모든 태그를 가져오는 것은 다음과 같습니다.
SELECT Tags.TagId,Tags.TagName
FROM Tags,TagXref
WHERE TagXref.TagId = Tags.TagId
AND TagXref.ItemID = @ItemID
태그에 대한 모든 항목을 가져오려면 다음과 같은 방법을 사용합니다.
SELECT * FROM Items, TagXref
WHERE TagXref.TagId IN
( SELECT Tags.TagId FROM Tags
WHERE Tags.TagName = @TagName; )
AND Items.ItemId = TagXref.ItemId;
여러 태그를 함께 사용하려면 위의 문장을 약간 수정하여 AND 태그를 추가해야 합니다.TagName = @TagName1 및 태그입니다.TagName = @TagName2 등...쿼리를 동적으로 작성합니다.
제가 하고 싶은 것은 원시 데이터를 나타내는 여러 테이블을 갖는 것입니다. 그래서 이 경우에는
Items (ID pk, Name, <properties>)
Tags (ID pk, Name)
TagItems (TagID fk, ItemID fk)
이렇게 하면 쓰기 시간에 빠르게 작동하고 모든 것이 정상화되지만 각 태그에 대해 테이블을 두 번 조인하여 원하는 추가 태그마다 테이블을 두 번씩 조인해야 하므로 읽는 속도가 느릴 수도 있습니다.
읽기를 개선하는 솔루션은 기본적으로 데이터를 플랫 형식으로 나타내는 새 테이블을 생성하는 저장 프로시저를 설정하여 명령 시 캐싱 테이블을 생성하는 것입니다.
CachedTagItems(ID, Name, <properties>, tag1, tag2, ... tagN)
그런 다음 태그가 지정된 항목 테이블이 모든 삽입에 있는 경우 해당 테이블을 최신 상태로 유지해야 하는 빈도를 고려한 다음 커서 삽입 이벤트에서 저장 프로시저를 호출할 수 있습니다.시간당 작업인 경우 시간당 작업을 설정하여 실행합니다.
이제 데이터 검색을 매우 영리하게 수행하려면 태그에서 데이터를 가져오는 저장 프로시저를 만들어야 합니다.대규모 사례 문에서 중첩된 쿼리를 사용하는 대신 데이터베이스에서 선택할 태그 목록이 포함된 단일 매개 변수를 전달하고 항목의 레코드 집합을 반환하려고 합니다.이것은 비트 연산자를 사용하는 이진 형식이 가장 좋습니다.
이진 형식에서는 쉽게 설명할 수 있습니다.항목에 할당할 태그가 4개 있다고 가정하면 이진법으로 다음을 나타낼 수 있습니다.
0000
네 개의 태그가 모두 개체에 할당된 경우 개체는 다음과 같이 표시됩니다.
1111
처음 두 개만...
1100
그러면 원하는 열의 1과 0으로 이진수 값을 찾는 경우입니다.SQL Server의 Bitwise 연산자를 사용하면 매우 간단한 쿼리를 사용하여 첫 번째 열에 1이 있는지 확인할 수 있습니다.
자세한 내용은 이 링크를 참조하십시오.
다른 사람들이 말한 것을 바꿔 말하면, 속임수는 스키마에 있는 것이 아니라 쿼리에 있습니다.
엔티티/라벨/태그의 단순한 스키마가 올바른 방법입니다.그러나 지금까지 보신 것처럼 태그가 많은 AND 쿼리를 수행하는 방법은 즉시 명확하지 않습니다.
해당 쿼리를 최적화하는 가장 좋은 방법은 플랫폼에 따라 다르므로 RDBS로 질문에 태그를 다시 지정하고 "태그 데이터베이스에서 최적의 수행 및 쿼리 방법"과 같은 제목으로 변경하는 것이 좋습니다.
MS SQL에 대한 몇 가지 제안이 있지만, 사용 중인 플랫폼이 아닐 경우에는 삼가겠습니다.
위 답변의 변형은 태그 ID를 가져와서 정렬하고 ^ 구분 문자열로 결합하여 해시하는 것입니다.그런 다음 항목에 해시를 연결합니다.태그의 각 조합은 새 키를 생성합니다.AND 검색을 수행하려면 지정된 태그 ID로 해시를 다시 만들고 검색합니다.항목의 태그를 변경하면 해시가 다시 생성됩니다.태그 집합이 동일한 항목은 동일한 해시 키를 공유합니다.
언급URL : https://stackoverflow.com/questions/48475/database-design-for-tagging
'programing' 카테고리의 다른 글
SpringBoot에서 콩을 추가하는 방법시험 (0) | 2023.07.29 |
---|---|
"cdecl"은 무엇의 약자입니까? (0) | 2023.07.29 |
시스템 교체.Data.Oracle Client에서 Oracle로.데이터 액세스(ODP).NET) (0) | 2023.07.29 |
플라스크에서 'Imtable MultiDict'에서 데이터를 가져오는 방법 (0) | 2023.07.29 |
인덱스 이름이 Mysql의 전체 데이터베이스에서 고유해야 합니까? (0) | 2023.07.29 |