Sample Header Ad - 728x90

SQL Server: Using Service Broker to parallely run several stored procedures

2 votes
1 answer
1381 views
I need to use Service Broker in order to run several stored procedures parallelly (instead of sequentially). Please be aware that I need to use Service Broker, not alternative solutions such as SSIS or SQL Agent Jobs. I use SQL Server 13.0 (2016), SSMS 19.0 as well as AdventureWorksDW2016 as a database. Unfortunately, the very few implementations I could find online do not work for me. Also I have tried writing a script myself. I do not really get any issues, however, I have provided a table to store the starttime and endtime of my procedures, and unfortunately when I execute the procedures, I can see that they are being executing after the procedure before is finished. My script looks like so: Do you see what I am doing wrong or do you perhaps have a good implementation online? The ones that I have found, did not really help me. -- enable Service Broker; might be enabled by default --alter database [AdventureWorksDW2016_2] set enable_broker with rollback immediate; --Create a Service Broker queue and service for the stored procedure: CREATE QUEUE parallel_proc_queue; CREATE SERVICE parallel_proc_service ON QUEUE parallel_proc_queue; --Create a stored procedure that sends a message to the Service Broker queue and executes the desired stored procedure CREATE PROCEDURE send_parallel_proc_message @proc_name VARCHAR(100) AS BEGIN DECLARE @conversation_handle UNIQUEIDENTIFIER BEGIN DIALOG CONVERSATION @conversation_handle FROM SERVICE parallel_proc_service TO SERVICE 'parallel_proc_service' ON CONTRACT parallel_proc_contract WITH ENCRYPTION = OFF; SEND ON CONVERSATION @conversation_handle MESSAGE TYPE parallel_proc_message (@proc_name); EXECUTE @proc_name; END CONVERSATION @conversation_handle; END --Create a stored procedure that receives messages from the Service Broker queue and executes the stored procedure specified in the message: CREATE PROCEDURE parallel_proc_receiver AS BEGIN DECLARE @message_body VARCHAR(100) DECLARE @conversation_handle UNIQUEIDENTIFIER WHILE (1=1) BEGIN WAITFOR ( RECEIVE TOP(1) @message_body = message_body, @conversation_handle = conversation_handle FROM parallel_proc_queue ), TIMEOUT 1000; IF (@@ROWCOUNT = 0) BREAK; EXECUTE @message_body; END CONVERSATION @conversation_handle; END END -- define the contract for the Service Broker conversation CREATE MESSAGE TYPE parallel_proc_message VALIDATION = WELL_FORMED_XML; CREATE CONTRACT parallel_proc_contract (parallel_proc_message SENT BY ANY); --Start the Service Broker conversation DECLARE @conversation_handle UNIQUEIDENTIFIER BEGIN DIALOG CONVERSATION @conversation_handle FROM SERVICE parallel_proc_service TO SERVICE 'parallel_proc_service' ON CONTRACT parallel_proc_contract WITH ENCRYPTION = OFF BEGIN CONVERSATION TIMER (@conversation_handle) TIMEOUT = 180000; -- 3 minutes --create table to measure time (to check if parallellity actually works) CREATE TABLE dbo.StoredProcedureLog ( SPName NVARCHAR(255), StartTime DATETIME, EndTime DATETIME ); --define stored procedures CREATE PROCEDURE usp_GetSalesForCustomer AS BEGIN WAITFOR DELAY '00:00:02'; -- Log the start time of the stored procedure INSERT INTO dbo.StoredProcedureLog (SPName, StartTime) VALUES ('usp_GetSalesForCustomer', GETDATE()); SELECT c.FirstName, c.LastName, SUM(f.SalesAmount) AS TotalSales FROM dbo.FactInternetSales f JOIN dbo.DimCustomer c ON c.CustomerKey = f.CustomerKey GROUP BY c.FirstName, c.LastName; -- Log the end time of the stored procedure UPDATE dbo.StoredProcedureLog SET EndTime = GETDATE() WHERE SPName = 'usp_GetSalesForCustomer' AND EndTime IS NULL; END CREATE PROCEDURE usp_GetProductSales AS BEGIN WAITFOR DELAY '00:00:04'; -- Log the start time of the stored procedure INSERT INTO dbo.StoredProcedureLog (SPName, StartTime) VALUES ('usp_GetProductSales', GETDATE()); SELECT p.EnglishProductName, SUM(f.SalesAmount) AS TotalSales FROM dbo.FactInternetSales f JOIN dbo.DimProduct p ON p.ProductKey = f.ProductKey GROUP BY p.EnglishProductName; -- Log the end time of the stored procedure UPDATE dbo.StoredProcedureLog SET EndTime = GETDATE() WHERE SPName = 'usp_GetProductSales' AND EndTime IS NULL; END CREATE PROCEDURE usp_GetTopSellingProducts AS BEGIN WAITFOR DELAY '00:00:06'; -- Log the start time of the stored procedure INSERT INTO dbo.StoredProcedureLog (SPName, StartTime) VALUES ('usp_GetTopSellingProducts', GETDATE()); SELECT TOP 10 p.EnglishProductName, SUM(f.SalesAmount) AS TotalSales FROM dbo.FactInternetSales f JOIN dbo.DimProduct p ON p.ProductKey = f.ProductKey GROUP BY p.EnglishProductName ORDER BY TotalSales DESC; -- Log the end time of the stored procedure UPDATE dbo.StoredProcedureLog SET EndTime = GETDATE() WHERE SPName = 'usp_GetTopSellingProducts' AND EndTime IS NULL; END --Call the send_parallel_proc_message procedure for each stored procedure you want to execute in parallel: EXEC dbo.send_parallel_proc_message 'usp_GetSalesForCustomer'; EXEC dbo.send_parallel_proc_message 'usp_GetProductSales'; EXEC dbo.send_parallel_proc_message 'usp_GetTopSellingProducts'; --Start the parallel_proc_receiver stored procedure to execute the stored procedures in parallel EXEC parallel_proc_receiver; --check start and endtime of procedures, starttime should be the same select * from StoredProcedureLog
Asked by Jessy (21 rep)
Apr 4, 2023, 12:05 PM
Last activity: May 3, 2024, 08:40 PM