2012-01-11 1 views
2

Я пишу свой собственный веб-гусеничный агент. В настоящее время я сохраняю URL-адреса напрямую как uri.absoluteurl. Поэтому, когда я запрашиваю базу данных, добавлен ли этот url или нет, я напрямую запрашиваю базу данных как select pageid from mytable where url='absoluteurl'. Я полагаю, что это вызывает дополнительный стресс в базе данных, потому что мой процессор i 7 @ 4.5 ghz почти всегда на 100%.Web Crawler Url Хранение в базе данных - быстрый поиск URL-адресов - Hashing - C#

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

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

C# 4.0, MS-SQL 2008

Пример: http://img62.imageshack.us/img62/589/exampleimage.png

+1

Я подозреваю, что есть указатель на столбце URL-адреса? –

+0

Eugen Rieck, пожалуйста, посмотрите на это изображение: http://img62.imageshack.us/img62/589/exampleimage.png – MonsterMMORPG

+0

Это выглядит странно - в плане запроса отображаются нерадивые CPU, некоторые затраты на ввод-вывод (это то, что я ожидать). Является ли процессор доступным для пользователя или ядром? –

ответ

3

Поскольку у вас уже есть индекс на столбце Url, мое предположение является SELECT (получить PageId), то, если он не существует ВСТАВИТЬ (новый URL-адрес) является причиной того, что процессор достигает максимума. Если у вас искатель имеет несколько потоков, вы можете обменивать механизмы параллелизма/блокировки в SQL на tblPages.

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

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

SELECT PageId FROM tblPages WHERE HashedUrl=CHECKSUM(@url) AND [email protected] 

Теперь ТОЛЬКО ставьте индекс столбца на HashedUrl (не PageUrl). Индекс должен быть НЕ УНИКАЛЬНЫм из-за возможности коллизий. Это даст вам самые быстрые INSERT и SELECT до тех пор, пока вы не начнете получать число строк таблицы более 4 миллиардов, и в этом случае количество столкновений INT CHECKSUM вызовет много частичного сканирования таблицы в неиндексированном столбце PageUrl.

UPDATE

Вот простой код тест я использовал

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 spec ~ 4kb) будет больше 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 Гуру сам по себе, может быть, моему методу тестирования не является наиболее точным/полезно, но тема очень интересна в отношении не разумного пользователя конца оптимизации по сравнению с «черным ящиком» ,

+0

У меня недавно было что-то похожее. Разве индекс на url не может делать умные вещи, например, используя хеши/контрольные суммы внутри для более быстрого индексации? Я задал этот вопрос: http://stackoverflow.com/questions/7954602/creating-a-hashcode-for-use-in-a-database-ie-not-using-gethashcode, к которому большинство ответов было «не вставлять» хэш-код/​​контрольная сумма, просто позвольте базе данных беспокоиться об этом ». – Chris

+0

Есть много «просто позвольте {x] беспокоиться об этом» в stackoverflow. Я боюсь за инновации и навыки решения проблем в будущем, когда мы всегда полагаемся на других, чтобы решать проблемы, которые мы можем легко решить. В любом случае - добавить мои маленькие два цента к этому комментарию (без добавления какой-либо фактической информации): выполнить тест - время в обоих направлениях с приличным набором проб. Если он превратит наш SQL быстрее, не вставляя хэш, тогда GJ Microsoft - если нет, то GJ MonsterMMORPG вы получите свое приложение быстрее и узнали еще один трюк для вашего инструментального инструмента. –

+0

Большое спасибо за ответ. Теперь я просматриваю только определенные сайты. Поэтому я могу четко сказать, что общее количество URL-адресов никогда не превысит 10 миллионов. Я полагаю, что вероятность столкновения очень низкая из 10 м. И это не очень важная проблема, поэтому я могу принять несколько столкновений с выгодой, чтобы иметь намного быстрее. – MonsterMMORPG