Хранение URL веб-сканера в базе данных - быстрый поиск URL - хеширование - C # - PullRequest
2 голосов
/ 11 января 2012

Я пишу свой собственный веб-сканер.В настоящее время я храню URL-адреса непосредственно как uri.absoluteurl.Поэтому, когда я запрашиваю базу данных, был ли этот URL уже добавлен или нет, я напрямую запрашиваю базу данных как select pageid from mytable where url='absoluteurl'.Я предполагаю, что это вызывает дополнительную нагрузку на базу данных, потому что мой процессор с частотой 7 @ 4,5 ГГц все время почти на 100%.

Так что мне пришло в голову, что если я также сохраню хеш-адреса md5 вбаза данных и поиск их, независимо от того, существует этот URL или нет, может увеличить скорость поиска.

Так что жду ваших идей по этому поводу.Для проверки того, существует ли этот URL в базе данных или нет, какой будет наилучший подход?

c # 4.0, MS-sql 2008

ПРИМЕР: http://img62.imageshack.us/img62/589/exampleimage.png

1 Ответ

3 голосов
/ 11 января 2012

Поскольку у вас уже есть индекс для столбца Url, я предполагаю, что это SELECT (get pageid), тогда, если он не существует, INSERT (новый URL) - это то, что заставляет процессор работать на максимуме.Если у вашего сканера есть несколько потоков, вы можете облагать налогом механизмы параллелизма / блокировки в SQL на tblPages.

Что касается вашего конкретного вопроса, я бы использовал CHECKSUM (crc) вместо HASHBYTES (md).CHECKSUM работает быстрее, он возвращает INT вместо VARBINARY, поэтому индексирование будет проще / быстрее.

Однако именно потому, что CHECKSUM возвращает INT, он склонен к конфликтам, поэтому вам также следует искать URL какИ предложение.

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

Теперь ТОЛЬКО поместите индекс столбца в HashedUrl (не PageUrl).Индекс должен быть НЕ УНИКАЛЬНЫМ из-за возможности коллизий.Это даст вам самые быстрые INSERT и SELECT, пока вы не начнете добираться до количества строк таблицы, превышающего 4 миллиарда, и в этом случае количество коллизий 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 мсек "vs" истекшее время = 10318 мс ", однако, более медленные (-30%) ВЫБОРЫ" истекшее время = 37 мс "vs" истекшее время = 28 мс ".

Еще одна интересная заметка - выне может "правильно" УКАЗАТЬ поле URL VARCHAR, потому что длина (в соответствии со спецификацией http ~ 4 КБ) будет превышать 900 байт (максимально допустимый размер ключа SQL 2008).В то время как 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 как таковой, возможно, мой метод тестирования не самыйточный / полезный, но тема очень интересная с точки зрения нецелесообразной оптимизации на стороне пользователя по сравнению с «черным ящиком».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...