我正在编写自己的网络抓取工具。目前我将网址直接存储为uri.absoluteurl
。因此,当我查询数据库是否已添加该URL时,我直接将数据库作为select pageid from mytable where url='absoluteurl'
查询。我想这会对数据库造成额外的压力,因为我的核心i 7 @ 4.5 ghz cpu几乎都是100%。
所以我想到,如果我还在数据库中存储md5哈希的urls并查找它们是否存在该url可以提高查找速度。
等待你的想法。用于检查数据库中是否存在该URL,或者不是最佳方法?
c#4.0,MS-sql 2008
示例:
答案 0 :(得分:3)
由于您已经在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%)INSERTS"经过时间= 7339 ms" vs"经过时间= 10318 ms"然而,较慢(-30%)SELECTS"经过时间= 37 ms" vs"经过时间= 28 ms"。
另一个有趣的注意事项是你可以正确地"#34; INDEX一个URL VARCHAR字段,因为长度(根据http规范~4kb)将大于900字节(SQL 2008' s最大允许密钥大小)。虽然SQL仅对此发出警告,但警告确实注意到某些INSERTS / UPDATES可能会失败。
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 Guru,也许我的测试方法不是最准确/最有用的,但是关于不合理的用户端优化而不是'黑匣子'。