c# - 网络爬虫 URL 存储在数据库中 - 快速 URL 查找 - 哈希 - C#

标签 c# sql url web-crawler store

我正在编写自己的网络爬虫。目前我将 url 直接存储为 uri.absoluteurl 。因此,当我查询数据库是否已添加该网址时,我直接查询数据库 select pageid from mytable where url='absoluteurl' 。我想这会对数据库造成额外的压力,因为我的核心 i 7 @ 4.5 ghz cpu 几乎一直处于 100%。

所以我想到如果我也将 url 的 md5 哈希值存储在数据库中并查找它们是否存在该 url 可以提高查找速度。

所以等待你对此的想法。要检查该 url 是否存在于数据库中,最好的方法是什么?

c# 4.0,MS-sql 2008

示例:http://img62.imageshack.us/img62/589/exampleimage.png

最佳答案

由于 Url 列上已经有索引,我猜测是 SELECT(获取 pageid),然后如果它不存在,则 INSERT(新 URL)是导致 CPU 达到峰值的原因。如果您的爬网程序有多个线程,您可能会对 tblPages 上的 SQL 中的并发/锁定机制造成负担。

关于您的具体问题,我会使用 CHECKSUM (crc) 而不是 HASHBYTES (md)。 CHECKSUM 更快,它返回 INT 而不是 VARBINARY,因此索引会更容易/更快。

但是,正是因为 CHECKSUM 返回 INT,所以很容易发生冲突,因此您还应该将 URL 作为 AND 子句进行搜索。

SELECT PageId FROM tblPages WHERE HashedUrl=CHECKSUM(@url) AND PageUrl=@url

现在只在 HashedUrl(而不是 PageUrl)上放置列索引。由于可能发生冲突,索引必须是非唯一的。这将为您提供最快的 INSERT 和 SELECT,直到您的表行数开始超过 40 亿,在这种情况下,INT CHECKSUM 冲突的数量将导致对未索引的 PageUrl 列进行大量部分表扫描。

更新

这是我使用的简单基准代码

GO
/* NORMAL METHOD */
BEGIN
SET STATISTICS TIME ON
--
IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE ID = OBJECT_ID(N'tempdb..#Store1'))
BEGIN
    DROP TABLE #Store1
END
-- Normal
CREATE TABLE #Store1 (Id INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED, Data VARCHAR(4000))
CREATE UNIQUE CLUSTERED INDEX CIX_STORE1_DATA ON #Store1(Data)
-- Help Create Data
DECLARE @Data TABLE(Data VARCHAR(4000))
INSERT INTO @Data(Data) VALUES ('red.'), ('YELLOW/'), ('green'), ('.BLUE'), ('/violet'), ('PURPLE-'), ('-orange')
-- The data set we'll use for testing
INSERT INTO @Data
    SELECT a.Data + b.Data + c.Data + d.Data + e.Data + f.Data + g.Data 
    FROM @Data a, @Data b, @Data c, @Data d, @Data e, @Data f, @Data g
-- INSERTION TESTS
PRINT('INSERT INTO NORMAL')
INSERT INTO #Store1(Data)
    SELECT Data FROM @Data
-- SELECTION TESTS
PRINT('SELECT FROM NORMAL')
SELECT TOP 5000 d.Data, (SELECT s.Id FROM #Store1 s WHERE s.Data = d.Data) FROM @Data d 
--
SET STATISTICS TIME OFF
END 
GO
/* USING YOUR OWN CHECKSUM/HASH */
BEGIN
SET STATISTICS TIME ON
--
IF EXISTS(SELECT * FROM tempdb.dbo.sysobjects WHERE ID = OBJECT_ID(N'tempdb..#Store2'))
BEGIN
    DROP TABLE #Store2
END
-- With Hash
CREATE TABLE #Store2 (Id INT IDENTITY(1,1) PRIMARY KEY NONCLUSTERED, Hsh INT, Data VARCHAR(4000))
CREATE CLUSTERED INDEX CIX_STORE2_CRC ON #Store2(Hsh)
-- Help Create Data
DECLARE @Data TABLE(Data VARCHAR(4000))
INSERT INTO @Data(Data) VALUES ('red.'), ('YELLOW/'), ('green'), ('.BLUE'), ('/violet'), ('PURPLE-'), ('-orange')
-- The data set we'll use for testing
INSERT INTO @Data
    SELECT a.Data + b.Data + c.Data + d.Data + e.Data + f.Data + g.Data 
    FROM @Data a, @Data b, @Data c, @Data d, @Data e, @Data f, @Data g
-- INSERTION TESTS
PRINT('INSERT INTO CHECKSUM/HASH')
INSERT INTO #Store2(Hsh, Data)
    SELECT CHECKSUM(Data), Data FROM @Data
-- SELECTION TESTS
PRINT('SELECT FROM CHECKSUM/HASH')
SELECT TOP 5000 d.Data, (SELECT s.Id FROM #Store2 s WHERE Hsh = CHECKSUM(d.Data) AND Data = d.Data) FROM @Data d
--
SET STATISTICS TIME OFF
END 

结果(简而言之)我的方法实现更快(+30%)插入“耗时= 7339毫秒”与“耗时= 10318毫秒”,但是,较慢(-30%)选择“耗时= 37毫秒”与“耗时 = 28 毫秒”。

另一个有趣的注意事项是您无法“正确”索引 URL VARCHAR 字段,因为长度(根据 http 规范 ~4kb)将大于 900 字节(SQL 2008 允许的最大键大小)。虽然 SQL 仅对此给出警告,但该警告确实指出某些插入/更新可能会失败。

Warning! The maximum key length is 900 bytes. The index 'CIX_STORE1_DATA' has maximum length of 4000 bytes. For some combination of large values, the insert/update operation will fail.

我本身不是 SQL 专家,也许我的测试方法不是最准确/最有用的,但这个主题非常有趣,涉及不明智的用户端优化与“黑匣子”。

关于c# - 网络爬虫 URL 存储在数据库中 - 快速 URL 查找 - 哈希 - C#,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8819133/

相关文章:

c# - 什么是 TransactionScope 默认超时值?

c# - 错误 '' 'csc '' is not recognized as an internal or external cmd,operable program or batch file'

c# - 不直接返回任务时最恰本地使用 Async/Await?

c# - async 和 await 不起作用

mysql - 一对多仅返回一个结果

java - MalformedURLException 虽然我已经用 %20 替换了空格

c# - 在 Xamarin Master-Detail MVVM 设置中,如何从 subview 的 View 模型中触发事件并让它被父 View 的 View 模型捕获

sql - 将临时表重命名为物理表

css - css中背景图像的url属性

php - 如何获取上传到 FTP 服务器的文件的 HTTP URL