在SQL Server中存储URL

时间:2010-08-24 22:45:30

标签: sql-server

使用SQL Server我想在表格中存储URL列表。另外,我要求我不希望任何URL更多地出现在表中。

这表明我想将URL作为表的主键,但由于URL的长度,这在SQL Server中是不可能的。 SQL Server有一个约束,即可以索引的字符字段的最大长度是900个字符,而根据规范的URL可能是无限的,实际上IE支持最多2k的URL,因此900太短了。

我的下一个想法是使用HashBytes函数创建URL的哈希值,以用作要编制索引的列。在这种情况下,可能存在两个不同的URL可能散列到相同的值(不太可能但可能),因此我不能使用唯一索引。

针对此表的大部分处理将是插入,这是我想要优化的性能。

我的想法是拥有一个URL列和一个Hashvalue列,并在Hashvalue上创建一个非唯一索引。

然后我将创建一个Trigger for Insert,如果插入的Hashvale =现有的Hashvalue并且Inserted URL =现有的URL,则会回滚插入。我希望查询优化器会使用索引来首先找到哈希值匹配的记录,然后不必进行全表扫描来尝试匹配URL。

我是在正确的轨道上还是有更好的方法来解决这个问题?

4 个答案:

答案 0 :(得分:2)

有更好的方法。

创建一个新字段int,将其设置为identity并自动递增。一般来说,使用字符串作为索引是非常糟糕的,但有一件事情,如果你想要稍后更改URL,无论出于什么原因你将不得不更新所有外键,这很快就会变得可怕。如果你有一个gabillion URL,你的数据库大小将会膨胀,一个简单的int字段会缩小大小。

我有时认为我可以使用其他字段作为主键,但是选择int字段和男孩我很高兴我做到了这一点。

除非我误解了这个问题。您希望多久插入一次网址?您很可能低估了数据库的功能。他们可以非常快速地执行大量查询。做一些测试!在插入之前,没有理由可以使用快速选择语句检查URL。

或者您可以随意插入,然后在以后执行批处理作业以删除重复项。

或者你可以将它们排队插入。

我会保持简单。我认为您可能对数据库对基本查询的速度有多惊讶,它们的设计考虑到了这一点。

在我看来,你最大的问题是如何存储URL,有很多东西可以通过多种方式解释。例如,不是包括域(COM,CO.UK等),而是为什么不将它更多地标准化并单独存储域扩展并且具有链接具有后缀/前缀/协议的域的表。另请注意,在某些边缘情况下,http://www.example.com可能与http://example.com不同。

如果你做到更高级别的标准化,那么你的约束和唯一身份将会变得非常复杂,无法管理。

有很多想想!确保你设计得很好。

答案 1 :(得分:0)

听起来像你想要使用INT作为主键并在URL_column上使用UNIQUE CONSTRAINT。

  

创建唯一约束以确保   没有输入重复值   没有的特定列   参加主键。而   既有唯一约束又有主要约束   关键的执行唯一性,你应该   附加一个唯一约束而不是   表的主键约束   如果:

     

•您希望在a中强制执行唯一性   列或列的组合。您   可以附加多个唯一约束   到桌子,而你可以附加   只有一个主键约束   表

     

•您希望在a中强制执行唯一性   允许空值的列。您   可以附加唯一约束   允许空值的列,   而你可以附加主键   约束只对那些列   不允许空值。当你附上   列的唯一约束   允许空值,你确保   最多一行将具有空值   在约束列中。

     

创建唯一约束

     

1.在对象资源管理器中,右键单击要添加的表   唯一约束,然后单击“设计”   (在SP1或更早版本中修改)。

     

该表在表设计器中打开。

     

2.从Table Designer菜单中,单击Indexes / Keys。

     

3.在“索引/键”对话框中,单击“添加”。

     

4.在网格中,单击“类型”,然后从下拉列表框中选择“唯一键”   在酒店右侧。

     

创建唯一约束   保存表时的数据库。

msdn LINK

答案 2 :(得分:0)

我会重新考虑两个网址生成相同哈希值的概率。

根据MVP Michael Coles的说法:

  

产生碰撞的几率   160位散列函数是2 ^ 80。   也就是说你可以期待一个   生成哈希值后发生碰撞   为1,208,925,819,614,629,174,706,176   数据行。

然后,他向任何能够生成一个人的人提供$100 bounty

我能够加载100万个唯一字符串(每个字符1944个字符),带有计算的哈希列(以及列上的唯一约束),没有违规行为:

/* Test table */
CREATE TABLE #t (
  URL VARCHAR(2000) NOT NULL
) 
GO

/* Computed column */    
ALTER TABLE #t ADD HB_URL AS (HASHBYTES('SHA1', URL))
GO

/* Unique constraint on computed column */
ALTER TABLE #t ADD CONSTRAINT HB_URL_UQ UNIQUE (HB_URL)
GO

加载数据(约5分钟):

INSERT #t (URL) 
SELECT TOP 1000000
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) + 
  CAST(NEWID() AS VARCHAR(36)) + CAST(NEWID() AS VARCHAR(36)) 
FROM sys.all_objects s1 
CROSS JOIN sys.all_objects s2

测试无效行:

DECLARE @x VARCHAR(2000)
SELECT TOP 1 @x = URL FROM #t
INSERT #t (URL) VALUES (@x) 

/* 
Msg 2627, Level 14, State 1, Line 4
Violation of UNIQUE KEY constraint 'HB_URL_UQ'. 
Cannot insert duplicate key in object 'dbo.#t'.
The statement has been terminated.
*/

答案 3 :(得分:0)

不确定这是你在做什么,但是在叙述我面临的类似情况:

对于我们的网站,我们使用了一个表来存储完整的URL及其相应的RewritePath(我使用的是ASP.NET)。 RewritePath映射到实际页面ex。 Default.aspx,一个SEF(搜索引擎友好)URL ex。 /家,指向。

虽然我在数据库中使用此URL存储(在我的情况下,它大约是100K URL)作为内存缓存的持久存储,而不是每次从数据库查询URL。

我发现由于内存缓存用于检索SEF到RewritePath映射,我们的网站速度已大大提高。我用过

 IDictionary<string, string> 

为此。

注意:在此实现中,我得到的主要问题是并发请求的线程安全性。

为了消除这些并发问题,我们更改了插入中的隔离级别(通过SP),该隔离级别已在事务中完成,并且还检查了现有的SEFURL(如果有)。它在我们的情况下也应该是唯一的,因此在插入之前使用了检查。

可能对你有所帮助。