2011-05-15 112 views
0

我需要在SQL表中存储短标签(A01,B34等),并确保它们的索引。为字母表中的每个字母创建INT列是不可能的,因为例如条目可以有多个“A”标签。SQL - 如何标记数据?

首先我将它们存储为一个长字符串,用空格分隔(例如“A01 B34”)。但是这需要一个LIKE%查询,它执行完整的扫描并忽略任何索引。所以我正在寻找替代品。

我现在使用SQLite FTS(文本搜索)来搜索这些标签,但是这需要一个特殊的表来存储标签,并通过JOIN查询获取结果,以及其他所有我喜欢的东西避免。

我的要求很简单:我需要存储数百万个短字符串,每个字符串都有自己的标签,并对这些标签进行简单搜索。

我目前的做法(在标签上执行FTS)最快吗?或者,使用NoSQL数据库来处理这种数据会更好吗?

+0

标签代表什么?也许这会帮助我们想象这个问题。 FTS似乎有点过分。 – 2011-05-15 14:02:12

+0

他们代表类别。以IMDB为例,其中每部电影有多个流派。 – Muis 2011-05-15 14:05:27

回答

1

我将分享我的经验,我在之前的启动Pageflakes社区网站上如何做到这一点。在Pageflakes中,用户创建的内容被标记。从这里你可以看到一个例子:

http://www.pageflakes.com/Community/Content/Flakes.aspx?moduleKey=4796

每个窗口小部件,pagecast有标签的集合。当有人搜索时,我们给予标签最高优先级,然后标题,然后描述项目。

假设你有一个表的内容是这样的:

Content (id, title, description) 

首先,你需要创建一个表的所有独特标签。

Tag (id, name (unique), countOfItems) 

然后,您需要将标签映射到内容行。

TagContentMap (tagid, contentid) 

您现在要问,对于每个新内容,我必须插入三个表格。不总是。只有当您有新标签时才可以插入标签表格。大多数时候,人们选择现有的标签。经过几个月的标记后,用户应该已经用尽了独特的标签。从那时起,99%的时间用户选择一些现有的标签。所以,这为您删除了一个插入。所以,你只有一个额外的插入。

此外,insert总是显着低于select。很可能你会有99%的阅读,1%的写作。

除非您介绍这两个表格,否则您永远无法拥有一个用户界面,用户可以点击某个标签并查看标记有该特定标签的所有内容。如果您不需要这种功能,那么您当然可以在内容表格本身上添加一个“标签”列,并以逗号分隔的格式存储标签。

现在最重要的一点 - 如何产生最好的搜索结果。在内容表中,我们有一个名为“SearchData”的varchar字段。该字段首先填充标签名称,然后是标题,然后是说明。因此,

SearchData = tag names comma delimited + newline + title + newline + description. 

然后,您使用SQL Server的全文索引来索引仅SearchData列,而不是内容表中的任何其他字段。

这是否适合您?

+0

检查,这是否会为你工作? – oazabir 2011-05-18 10:44:54

+0

是的,非常有帮助! – Muis 2011-05-21 09:29:04

+0

可以将我的答复标记为答案吗? – oazabir 2011-05-30 06:11:43

1

你不会给我们很多细节,但你的设计似乎都是错误的。这不是第三范式。

0

@Joshua,请在术语“正常化”中使用goo。目前您的数据是非规范化的。非规范化是可能的事情。但在正常化之后,以及某种性能受到破坏。目前你的设计似乎是错误的。

正如你应该有1台3台insetad一个例子:

some_records (id, column1, ..., columnN) 
tags (id, title) 
some_records_tags (some_record_id, tag_id) 

这是一个在DBMS经典的设计模式。这里不需要NoSQL。

+0

我知道规范化,你说得对,这个1表设计不是靠书本。但是我必须存储/搜索非常大量的数据,甚至每次优化(PRAGMA,批量事务)仍然太慢。如果我使用上述表格,我必须每次更新至少添加3行(而不是1)。如果没有性能损失,我会很乐意改变设计。 – Muis 2011-05-15 16:20:24

+0

@Joshua,如果你的应用数据变化与读取的数据是1到9999之间的东西,那么你应该做“按书”。请记住,当你插入/更新内容时,你的应用程序不适合你,但是对于用户来说,大部分时间都是从中读取数据。无论如何,为了获得更高级的性能,你可以使用一些缓存系统,但是在数据库层,我建议你采用经典的方式。插入一个新标签并不是一项艰巨的任务,也可以在一个SQL中插入some_records + some_records_tags。这是所有可能的。 – gaRex 2011-05-15 16:27:21

0

正如其他用户指出的那样,数据的标准化程度并不高。我会假设这是有意的,并且有一些非常大的(gb或tb大小的要求或者没有提到的巨大吞吐量要求)。但是在你开始任何路径之前,你应该准确理解你的需求是什么:你写和读的频率,写和读的延迟要求是多少,你必须在你的计算中包括索引维护。

如果您有明显的性能需求,您可以尝试在当前拥有的基础上构建一个近线索引系统。过去我使用这种技术来处理大吞吐量需求系统。这个想法基本上是为了写入,你尽可能小而快地创建它们,然后创建一个批处理返回并将数据添加到辅助搜索表中,以便将其转换为能够搜索的表单。好处是您的写入操作可以快速完成,并且如果您选择了聚簇索引,那么可以非常有效地完成批处理的读取操作。另外,您可以根据需要将数据分段到不同的服务器,以支持更高的搜索吞吐量。主要缺点是更新不会即时反映在搜索结果中。

如果你写到一个表所示: 表数据(ID二进制(6),...,时间戳日期时间,标记为varchar(256))

,并有一个辅助表: 表搜索(标签char(3),dataId binary(6))

您可以创建一个批处理过程,以获取最后一个BATCH_SIZE(1000个可能)记录并将标记列拆分为一个空格并将标记插入/从搜索表格。您将变量/行保留在您收集的最后一个时间戳值的某处,并在下一个批处理间隔从那里开始。最后,如果删除很重要,则每个批处理间隔都需要在数据表中找到不再存在的一组记录。或者,如果您的数据表太大,或者您可以同时对数据执行删除操作,并搜索它们不经常发生的情况,您可以选择逻辑删除表。

需要注意的事情与批处理正在使批量大小过大,并更新搜索表时采取表锁。此外,你必须注意重复的时间戳。当然,在写入/更新数据表时,必须始终更新时间戳。