【问题标题】:Dedicated SQL table containing only unique strings仅包含唯一字符串的专用 SQL 表
【发布时间】:2012-05-29 00:51:01
【问题描述】:

我似乎在网络上找不到任何人这样做的例子,所以我想知道这是否有原因(或者我没有使用正确的搜索词)。甚至可能已经有一个我不知道的术语?

为了为定期重复出现的字符串节省数据库存储空间,我正在考虑创建一个名为 unique_string 的 MySQL 表。它只有两列:

  1. "id" : INT : PRIMARY_KEY 索引
  2. “字符串” : varchar(255) : 唯一索引

然后,数据库中任何位置的任何其他表都可以使用 INT 列而不是 VARCHAR 列。例如,名为 browser 的 varchar 字段将改为名为 browser_unique_string_id 的 INT 字段。

我不会将它用于性能重要的任何事情。在这种情况下,我使用它来跟踪每个页面请求的详细信息(记录 Web 统计信息)以及对 Intranet 上的用户操作的“审计试验”,但其他事情也可能如此。

我也知道 SELECT 查询会很复杂,所以我并不担心。我很可能会编写一些代码来生成查询以返回“真实”字符串数据。

想法?我觉得我可能在这里忽略了一些明显的东西。

谢谢!

【问题讨论】:

  • 我可能错过了您想要做的事情,但是您的描述听起来完全像数据库规范化的香草最佳实践; stackoverflow.com/questions/723998/…
  • Normalisation? - “数据库规范化是组织关系数据库的字段和表以最小化冗余和依赖性的过程。” - 来自维基百科
  • 我知道您想将 varchar 存储到带有 id 的表中,并且您将使用 ID 而不是 varchar 类型,对吧?
  • 是的,我想我问的原因是我还没有看到任何示例,其中有一个主字符串表在整个数据库中引用,绝对是字符串。通常会有多个表格,专门列出“某事”,例如职位表。
  • 您可能对 ARCHIVE 存储引擎感兴趣 - dev.mysql.com/doc/refman/5.5/en/archive-storage-engine.html - 它可以压缩数据,我敢打赌,与您在 SQL 查询 WRT 压缩中所做的相比,zlib 会做得很好。

标签: mysql sql sql-server database database-design


【解决方案1】:

我已将此结构用于类似的应用程序——跟踪 Web 日志的 URI。在本例中,数据库是 Oracle。

性能问题并非微不足道。随着数据库的增长,有数千万个 URI。因此,仅在 INSERT 期间识别正确的字符串是具有挑战性的。我们通过在 hadoop 中构建大部分更新逻辑来处理这个问题,因此数据库表本质上只是一个 hadoop 表的副本。

在常规数据库中,您可以通过构建索引来解决此问题,正如您在问题中所建议的那样。而且,索引解决方案可以很好地满足您的可用内存。实际上,这对于索引来说是一种相当退化的情况,因为您实际上只需要索引而不需要基础表。我不知道 mysql 或 SQL Server 是否可以识别这一点,尽管列式数据库(例如 Vertica)应该。

SQL Server 有另一个选项。如果您将字符串声明为 VARCHAR(max),则它不会与其余数据存储单独的数据页。在全表扫描期间,如果查询中没有引用该列,则无需在内存中加载额外的页面。

【讨论】:

  • 谢谢,是的,当索引变大时,事情会变得很有趣。对于这个项目,我认为应该没问题,因为只有大约 10 个 URL 和一组有限的浏览器等。我只会将它用于定期重复出现的字符串。
【解决方案2】:

这是数据库中非常常见的设计模式,其中数据的基数与其链接的事务表相比相对较小。查询不会很复杂,只是对查找表的简单连接。您可以在查找表中不仅包含一个字符串,还可以包含通常重复的其他信息。您只需 normalizing 您的模型即可删除重复数据。

例子:

请求表:

Date    
Time   
IP Address    
Browser_ID  

浏览器表:

Browser_ID
Browser_Name
Browser_Version
Browser_Properties

【讨论】:

  • 感谢您的回复。我想我的问题可以更具体一些。我问更多关于为任何类型的数据拥有一个主字符串表,它在整个数据库中使用,而不是为特定实体提供多个字符串表。
  • 用 id 号替换文本与规范化无关。而且您不会删除重复数据;您正在用重复的数字替换重复的文本。
  • 如果您的主表中有“浏览器名称,浏览器版本”,并将其替换为与“浏览器”表有 1-M 关系的主表上的外键,那么您已经从文件系统中删除重复数据并用一个键替换它。 外键是规范化的重要组成部分。 en.wikipedia.org/wiki/Foreign_key
【解决方案3】:

如果您计划实时记录数据(而不是批处理作业),那么您希望确保尽可能快地将记录写入数据库。如果您正在同步记录,那么显然记录创建时间将直接影响 http 请求完成所需的时间。如果这是异步的,那么缓慢的记录创建时间将导致瓶颈。但是,如果这是批处理作业,那么只要您可以在下一个批处理运行之前自信地创建所有批处理记录,那么性能就无关紧要了。

为了减少创建记录所需的时间,您确实想要扁平化数据库结构,您当前的伪查询可能看起来像

SELECT @id = id from PagesTable
WHERE PageName = @RequestedPageName

IF @id = 0
THEN 
  INSERT @RequestedPageName into PagesTable
  @id = SELECT @@IDENTITY 'or whatever method you db supports for              
                          'fetching the id for a newly created record
END IF

INSERT @id, @BrowserName INTO BrowersLogTable 

在平面结构中,您只需要 1 个 INSERT

如果您应该关注数据完整性,那么通常您会通过定期查询将这些数据写入一组单独的表(或单独的数据库)并将其用于查询来规范化这些数据。

【讨论】:

  • 太棒了,谢谢。这正是我没有想到的事情(即日志创建期间的性能)。就我而言,应该没问题。无论任何表中有多少“unique_string”字段,我都可以在 INSERT 之前使用一个初始 SELECT 查询提取所有 ID(假设这些值过去已经使用过,它们将大部分使用)。如果我的网站变得足够繁忙以至于这会减慢速度,那将是一个很棒的问题。 =)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
  • 1970-01-01
  • 2019-03-09
  • 2021-09-16
  • 1970-01-01
  • 2017-05-14
  • 2019-04-24
相关资源
最近更新 更多