删除SQL Server 2008数据库中的字符串重复

时间:2010-03-09 15:01:20

标签: sql database-design sql-server-2008 dictionary

后台:专业工具开发人员。 SQL / DB业余爱好者。

设置: .Net 3.5 winforms app与MS SQL Server 2008交谈。

场景:我使用从大量文件中提取的信息填充数据库。这相当于大约60M条记录,每条记录都有一个与之相关的任意大小的消息。我最初的计划是记录中的 nvarchar(max)字段来保存消息,但是在对数据子集执行测试运行之后,这将使数据库过大(推断为一个不可接受的113GB)。在这个初始测试数据集(1.3GB数据库)上运行一些查询我发现有大量的消息重复,我们可以使用它来将消息数据缩小到大约六分之一。我已经尝试并想到了一些实现这一目标的方法,但没有一个是令人满意的。我现在已经搜索了几天但是a)似乎没有一个好的答案(不太可能),或者b)我不知道如何表达我需要的东西(更有可能)。< / p>

考虑/尝试的方法:

  1. 使用 nvarchar(max)字段将邮件批量插入记录。 - 发现冗余太多。
  2. 坚持使用此消息列,但找到一种方法让数据库“压缩”消息。 - 不知道如何做到这一点。
  3. 为唯一消息添加消息表,键入主记录“指向”的ID。 - 在原则上工作时,实现独特性会变得很痛苦,并且随着更多消息的添加而减速。
  4. 在客户端上执行重复删除。 - 要求为每个填充会话将所有消息提取到客户端。这不会像他们需要适合内存那样扩展。
  5. 在消息表中添加一个额外的(索引的)哈希列,并使用相应的(本地生成的)哈希值提交消息。搜索此内容以缩小实际需要测试的消息。 - 复杂,必须有更好的方法。
  6. 第三种方法相当于创建字符串字典表。经过几次关于这个想法的迭代后,我得到了以下结论:

    1. 数据库有一个消息表,用于将(自动分配的) int ID主键映射到 nvarchar(max)消息。
    2. 客户端批量处理消息并提交多个记录以插入存储过程。
    3. 存储过程遍历一批传入记录,并为每条消息进行迭代:

      我。对于现有的消息实例,检查(SELECT)消息字典表。

      II。如果找到,请记住现有消息的ID。

      III。如果未找到,请插入新的消息记录,记住新记录的ID(OUTPUT)。

    4. 所有消息(旧的和新的)的ID都作为该过程的输出结果集返回。

    5. 客户端使用条目( int 外键)为使用从过程返回的ID填充的消息生成主表记录。
    6. 的问题:

      1. 随着消息数量的增加,对现有消息的搜索变得越来越慢,成为限制因素。
      2. 我尝试过索引(UNIQUE)消息列,但您无法索引 nvarchar( max 列。
      3. 我查看了MS SQL Server 2008的全文搜索功能,但这对我来说似乎有些过分。
      4. 我考虑过尝试在批量邮件中合并,但是我找不到一种方法可以轻松获取相应的ID列表(旧的和新的,,顺序)到回馈给客户。
      5. 在我看来,我正在尝试对数据进行某种规范化,但从我对数据库设计的理解来看,这更像是“行规范化”而非正确的规范化,这与“列规范化”有关。令我感到惊讶的是,这并不是所有需要相应支持的地方。

        所以,我的问题是:这里的方法是什么?

        非常感谢任何帮助。

        萨姆

3 个答案:

答案 0 :(得分:2)

Sam,我认为你正在使用方法#5 。而且我真的认为实施起来并不像你想象的那么复杂。本地生成的消息哈希很容易生成,它可以大大加快所有查找速度(在数据库上)。

当然,如果消息确实需要nvarchar(max)。如果你可以用更少的空间(我认为nvarchar为512)而不是你可以在SQL中使用唯一性约束和列中的索引来使搜索速度更快 - 绝对是我的建议,如果你认为你可以减少消息长度。

如果您使用消息哈希方法,我相信您也可以使用一种聪明的技术来加快速度。使用批量插入将所有记录插入数据库,而不必担心重复的消息。之后,您可以编写一个非常简单的查询来清除重复消息的消息表,然后继续强制执行唯一约束。

答案 1 :(得分:1)

您的文章中有解决方案。对于像nvarchar(max)这样的大数据,您需要减少搜索集 - 正如您所说:

  

添加额外(索引)哈希列   消息表并提交   具有相应的消息(本地   生成)哈希值。搜索这个   缩小消息   实际上需要测试。 -   复杂,必须有一个更好的   方式。

这是解决问题的方法。

或者如果您不想处理哈希值,请将前150个字符作为哈希值(例如varchar(150)),使用它来减少对重复项的搜索。它不会像hash,但取决于你的数据,它可能会工作。(你也可以使用75个第一个字符和75个最后的字符。)一些数据测试应该显示哪些区域是最独特的子字符串。

答案 2 :(得分:1)

归一化有两个实际方面(和原因):数据安排的敏感性(以及相应的维护保障)和性能。

关于敏感性,至少从抽象的数据库设计角度来看,您需要考虑的一个问题是数据是否真正重复。虽然您可能有两条具有相同数据的消息,但实际上它们可能并不代表“相同的东西”。真正的问题是:两条消息共享相同文本的事实是否会使它们成为相同的消息?换句话说,假设消息A和消息B共享相同的文本,您是否希望更改消息A将反映在消息B中?

如果您的回答是“是”,那么您的字符串字典是正确的方法。如果不是,那么确实没有重复的数据,只有看起来相同但不相同的数据。

从性能的角度来看,我可能认为带有附加消息哈希的字符串字典是最好的方法;我认为这并不像你认为的那么复杂。几乎所有语言(包括T-SQL)都提供标准哈希算法,在这种情况下,我不会认为冲突的可能性甚至哈希值的分布是非常重要的,因为你只是将它用作“提示“加快查询的执行速度。