Sql 标签数据库设计
如何设计数据库以支持以下标记功能:Sql 标签数据库设计,sql,database-design,tags,tagging,Sql,Database Design,Tags,Tagging,如何设计数据库以支持以下标记功能: 项目可以有大量的标记 搜索带有给定标记集的所有项目必须快速(项目必须具有所有标记,因此它是AND搜索,而不是OR搜索) 创建/写入项目的速度可能较慢,以实现快速查找/读取 理想情况下,使用(至少)一组n个给定标记标记的所有项的查找应该使用单个SQL语句完成。由于要搜索的标记数以及任何项上的标记数未知且可能很高,因此使用联接是不切实际的 有什么想法吗 谢谢你迄今为止的所有答案 但是,如果我没有弄错的话,给出的答案说明了如何在标签上执行OR搜索。(选择具有n
- 项目可以有大量的标记
- 搜索带有给定标记集的所有项目必须快速(项目必须具有所有标记,因此它是AND搜索,而不是OR搜索)
- 创建/写入项目的速度可能较慢,以实现快速查找/读取
谢谢你迄今为止的所有答案
但是,如果我没有弄错的话,给出的答案说明了如何在标签上执行OR搜索。(选择具有n个标记中的一个或多个标记的所有项目)。我正在寻找一个高效的搜索引擎。(选择所有有n个标签的项目,可能还有更多。)我认为简单的解决方案没有问题:项目表、标签表和“标签”交叉表 交叉表上的指数应足够优化。选择合适的项目是必要的
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 ...
而标签将是
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 ...
不可否认,对于大量比较标记来说,这并不是很有效。若要在内存中维护标记计数,可以使查询以不经常使用的标记开始,这样可以更快地计算和排序。根据要匹配的标签的预期数量和匹配任何一个标签的预期,这可能是一个不错的解决方案,如果要匹配20个标签,并且预期一些随机项将匹配其中15个,那么这对数据库来说仍然是一个沉重的负担。最简单的方法是创建一个标签表。
Target\u Type
——如果要标记多个表Target
——正在标记的记录的键标记
——标记的文本
查询数据可能类似于:
Select distinct target from tags
where tag in ([your list of tags to search for here])
and target_type = [the table you're searching]
SELECT Tags.TagId,Tags.TagName
FROM Tags,TagXref
WHERE TagXref.TagId = Tags.TagId
AND TagXref.ItemID = @ItemID
更新根据您的需求和条件,上面的查询将变成这样
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]
您将无法避免连接,并且仍然可以正常化 我的方法是创建一个标记表
TagId (PK)| TagName (Indexed)
然后,在items表中有一个TagXREFID列
此TagXREFID列是第三个表的FK,我将其称为TagXREF:
TagXrefID | ItemID | TagId
因此,获取一个项目的所有标记如下:
Select distinct target from tags
where tag in ([your list of tags to search for here])
and target_type = [the table you're searching]
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;
要将和一组标记放在一起,您需要稍微修改上面的语句,添加和tags.TagName=@TagName1和tags.TagName=@TagName2等,并动态构建查询。您可能需要尝试一种不严格的数据库解决方案,如实现(例如),并使用在此基础上构建的搜索引擎 此具有适当缓存机制的解决方案可能比国产解决方案产生更好的性能 但是,我并不认为在中小型应用程序中,您需要比前面文章中提到的规范化数据库更复杂的实现
编辑:根据您的说明,在搜索引擎中使用类似JCR的解决方案似乎更有说服力。从长远来看,这将大大简化您的程序。我喜欢做的是有许多表来表示原始数据,因此在本例中,您需要
Items (ID pk, Name, <properties>)
Tags (ID pk, Name)
TagItems (TagID fk, ItemID fk)
如果将所有四个标记指定给一个对象,该对象将如下所示
1111
如果只是前两个
1100
然后就是在你想要的列中找到带有1和0的二进制值。使用SQL Server的逐位运算符,可以使用非常简单的查询检查第一列中是否有1
查看此链接以找出答案。要解释其他人所说的话:诀窍不在模式中,而是在查询中 实体/标签/标记的朴素模式是正确的选择。但正如您所看到的,如何使用大量标记执行AND查询目前还不清楚 优化该查询的最佳方式取决于平台,因此我建议使用RDB重新标记您的问题,并将标题更改为类似“在标记数据库上执行和查询的最佳方式”
我对MS SQL有一些建议,但如果您使用的平台不是MS SQL,我将不再提这些建议。我支持@Zizzencs的建议,即您可能需要不完全以(R)DB为中心的东西 不知何故,我相信使用普通的nvarchar字段存储带有适当缓存/索引的标记可能会产生更快的结果。但那只是我 我以前使用3个表来表示多对多关系(Item Tags ItemTags)实现了标记系统,但我想你会在很多地方处理标记,我可以告诉你,3个表必须一直同时被操作/查询,这肯定会使你的代码更加复杂
你可能想考虑增加的复杂性是否值得。
< Po>关于Addio:听起来好像你正在寻找“关系划分”操作。以简明易懂的方式介绍关系划分关于性能:基于位图的方法听起来很适合这种情况。然而,我不认为“手动”实现位图索引是一个好主意,正如digiguru所建议的那样:无论何时添加新标记(?)听起来都是一个复杂的情况,但一些DBMS(包括Oracle)提供位图索引,这些索引可能在某种程度上是有用的,因为内置索引系统消除了索引维护的潜在复杂性;此外,提供位图索引的DBMS应该能够在执行查询计划时适当地考虑它们。 这是一篇关于标记数据库模式的好文章: 阿洛