我正在编写自己的网络爬虫。目前我将 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
示例:
最佳答案
由于 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/