3

Я сейчас в процессе создания веб-искателя на C#. Чтобы поставить очередь на URL-адреса, которые пока не выполняются, я использую SQL Server. Он работает очень быстро, но с течением времени он становится очень большим, что замедляет мои хранимые процедуры.Очередь приоритетов в SQL Server

CREATE TABLE PriorityQueue 
(
ID int IDENTITY(0,1) PRIMARY KEY, 
absolute_url varchar (400), 
depth int, 
priorty int, 
domain_host varchar (255), 
); 

CREATE INDEX queueItem ON PriorityQueue(absolute_url); 
CREATE INDEX queueHost ON PriorityQueue(domain_host); 

Это таблица, которую я использую для своей очереди. Приоритетные номера от 1 до 5 с 1 наивысшим приоритетом. Как вы можете видеть, я также использую индексы для моих хранимых процедур ниже.

Процедура добавления новых элементов в очереди:

DROP PROCEDURE IF EXISTS dbo.Enqueue 
GO 
CREATE PROCEDURE dbo.Enqueue(@absolute_url varchar(255), @depth int, @priorty int, @host varchar(255)) 
AS 
BEGIN 
    INSERT INTO [WebshopCrawler].[dbo].[PriorityQueue] (absolute_url, depth, priorty, domain_host) VALUES (@absolute_url, @depth, @priorty, @host); 
END 
GO 

Процедура для получения элемента с наивысшим приоритетом:

DROP PROCEDURE IF EXISTS dbo.Dequeue 
GO 
CREATE PROCEDURE dbo.Dequeue 
AS 
BEGIN 
    SELECT top 1 absolute_url, depth, priorty 
    FROM [WebshopCrawler].[dbo].[PriorityQueue] 
    WHERE priorty = (SELECT MIN(priorty) FROM [WebshopCrawler].[dbo].[PriorityQueue]) 
END 
GO 

Это один получает действительно медленно с большими данными.

Процедура удаления элемента из очереди:

DROP PROCEDURE IF EXISTS dbo.RemoveFromQueue 
GO 
CREATE PROCEDURE dbo.RemoveFromQueue(@absolute_url varchar(400)) 
AS 
BEGIN 
    DELETE 
    FROM [WebshopCrawler].[dbo].[PriorityQueue] 
    WHERE absolute_url = @absolute_url 
END 
GO 

Я пробовал использовать много различных индексов, но ничего не казалось, чтобы сделать процедуры идти быстрее. Надеюсь, у кого-то есть идея о том, как улучшить это.

ответ

3

Просьба ознакомиться с Using tables as Queues. Важные вопросы:

  • Вы должны организовать таблицу в соответствии с стратегией dequeue. Первичный ключ в IDENTITY совершенно не имеет смысла. Используйте кластерный индекс, основанный на приоритете и порядке деактивации.
  • Вы должны атомарно из очереди в одном операторе, используйте DELETE ... OUTPUT ...

Так оно и должно быть что-то вдоль этих линий:

CREATE TABLE PriorityQueue 
(
    priority int not null, 
    enqueue_time datetime not null default GETUTCDATE(), 
    absolute_url varchar (8000) not null, 
    depth int not null, 
    domain_host varchar (255) not null, 
); 

CREATE CLUSTERED INDEX PriorityQueueCdx on PriorityQueue(priority DESC, enqueue_time); 

CREATE PROCEDURE dbo.Dequeue 
AS 
BEGIN 
    with cte as (
     SELECT top 1 absolute_url, depth, priority 
     FROM [PriorityQueue] with (rowlock, readpast) 
     ORDER BY priority DESC, enqueue_time) 
    DELETE FROM cte 
     OUTPUT DELETED.*; 
END 
GO 
+0

'по умолчанию GETUTCDATE()' >> лучше дать это ограничение имя, а чем SQL Server назначить ему случайный. Я знаю, что это просто иллюстрация =), но люди могут вслепую скопировать его, думая, что хорошей практикой не назвать ограничений. –

+0

Во-вторых, нет гарантированной сортировки, если строки добавляются с тем же 'enqueue_time', что произойдет для быстрых вставок или когда у вас есть объемные вставки. Это будет противоречить идее очереди. –

+0

TT. Вы правы, я пробовал выше, и он работает хорошо, но URL-адреса могут быть вставлены одновременно с причиной многопоточности. –

Смежные вопросы