The overhead of entering a TRY block is relatively small, but the overhead of catching an exception is more substantial. If we manage to use CASE or IF to prevent an exception, we can noticeably improve performance. We shall run benchmarks and see for ourselves - in our example, catching an exception will be approximately nine times more expensive than exiting the TRY block without it.
Entering TRY blocks is not free
In this section we shall wrap the body of a stored procedure in a TRY CATCH block, and measure the overhead. The following procedure does not use a TRY CATCH block:
CREATE ALTER PROCEDURE dbo.PerformDivision
@dividend INT ,
@divisor INT ,
@Quotient INT OUT
AS
BEGIN;
SET NOCOUNT ON ;
SELECT @Quotient = CASE WHEN @divisor = 0 THEN NULL
ELSE @dividend / @divisor
END ;
RETURN @@ERROR ;
END ;
GO
Let us benchmark it. Whether the divisor is zero or not, the procedure runs at the same speed:
CREATE PROCEDURE dbo.PerformDivision100kTimes
@dividend INT ,
@divisor INT
AS
BEGIN ;
DECLARE @i INT ,
@Quotient INT ;
SET @i = 1 ;
WHILE @i <= 100000
BEGIN ;
EXEC dbo.PerformDivision @dividend = @dividend,
@divisor = @divisor, @Quotient = @Quotient OUT ;
SET @i = @i + 1 ;
END ;
END ;
GO
EXEC dbo.PerformDivision100kTimes
@dividend = 1 ,
@divisor = 1
-- cpu 1250 ms
GO
EXEC dbo.PerformDivision100kTimes
@dividend = 1 ,
@divisor = 0
-- cpu 1250 ms
GO
Let us remove the CASE expression, so that the division can raise an exception, and wrap the division operator in a TRY CATCH block:
ALTER PROCEDURE dbo.PerformDivision
@dividend INT ,
@divisor INT ,
@Quotient INT OUT
AS
BEGIN;
SET NOCOUNT ON ;
BEGIN TRY
SELECT @Quotient = @dividend / @divisor ;
END TRY
BEGIN CATCH
SELECT @Quotient = NULL ;
END CATCH ;
RETURN @@ERROR ;
END ;
GO
Even when the division does not raise an exception, the procedure runs 36% slower, 1703 ms vs 1250 ms:
EXEC dbo.PerformDivision100kTimes
@dividend = 1 ,
@divisor = 1
-- cpu 1703 ms
GO
Catching exceptions is a noticeable overhead
When the divisor is zero, and division does raise an exception that is caught in the CATCH block, the procedure runs 4.36 times slower, 5453 ms vs 1250 ms:
EXEC dbo.PerformDivision100kTimes
@dividend = 1 ,
@divisor = 0
-- cpu 5453 ms
GO
As we have seen, catching exceptions in CATCH blocks is slow. In this particular scenario, it is approximately nine times more expensive than just entering the TRY block.
If we manage to use CASE or IF to avoid an exception, we can noticeably improve performance.