SQL 服务器中的优先队列
Priority queue in SQL Server
我目前正在使用 C# 构建网络爬虫。要对尚未抓取的 URL 进行排队,我使用 SQL 服务器。它工作得非常快,但随着时间的推移它开始变得非常大,这会减慢我的存储过程。
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);
这是我用于队列的 table。优先级编号从 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
我尝试使用很多不同的索引,但似乎没有什么能让程序运行得更快。我希望有人知道如何改进它。
请阅读Using tables as Queues。重要问题:
- 您必须根据出队策略组织table。 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
我目前正在使用 C# 构建网络爬虫。要对尚未抓取的 URL 进行排队,我使用 SQL 服务器。它工作得非常快,但随着时间的推移它开始变得非常大,这会减慢我的存储过程。
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);
这是我用于队列的 table。优先级编号从 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
我尝试使用很多不同的索引,但似乎没有什么能让程序运行得更快。我希望有人知道如何改进它。
请阅读Using tables as Queues。重要问题:
- 您必须根据出队策略组织table。 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