SQL Server Stored Procedure Performance: The Critical Impact of ANSI_NULLS Settings

Nov 24, 2025 · Programming · 6 views · 7.8

Keywords: SQL Server | Stored Procedures | Performance Optimization | ANSI_NULLS | Execution Plans

Abstract: This article provides an in-depth analysis of performance differences between identical queries executed inside and outside stored procedures in SQL Server. Through real-world case studies, it demonstrates how ANSI_NULLS settings can cause significant execution plan variations, explains parameter sniffing and execution plan caching mechanisms, and offers multiple solutions and best practices for database performance optimization.

Problem Background and Phenomenon Analysis

In SQL Server database development, a perplexing phenomenon frequently occurs: identical SQL queries perform excellently when executed directly but suffer dramatic performance degradation when encapsulated within stored procedures. This article explores the root causes and solutions based on a real-world case study.

The core query in the case study is as follows:

DECLARE @SessionGUID uniqueidentifier
SET @SessionGUID = 'BCBA333C-B6A1-4155-9833-C495F22EA908'

SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

When executed directly, this query shows a subtree cost of only 0.502, indicating high efficiency. However, when the same logic is encapsulated in a stored procedure:

CREATE PROCEDURE dbo.ViewOpener @SessionGUID uniqueidentifier AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank

The execution cost surges to 19.2, representing nearly a 40-fold performance degradation. This performance disparity is common in database development, but the underlying causes are often overlooked.

Execution Plan Comparative Analysis

Comparing the two execution plans reveals significant differences:

Efficient Execution Plan Characteristics:

Inefficient Execution Plan Characteristics:

The key distinction lies in the inefficient plan's "eager spooling" operation, processing approximately 6 million rows, while the efficient plan avoids such resource-intensive operations.

Root Cause: ANSI_NULLS Setting Differences

Through thorough investigation, the problem根源 was identified in differing ANSI_NULLS settings. The critical findings are:

Slow Stored Procedure Definition:

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS OFF 
GO

CREATE PROCEDURE dbo.ViewOpener_Slow
    @SessionGUID uniqueidentifier
AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
GO

Fast Stored Procedure Definition:

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

CREATE PROCEDURE dbo.ViewOpener_Fast
    @SessionGUID uniqueidentifier 
AS
SELECT *
FROM Report_Opener
WHERE SessionGUID = @SessionGUID
ORDER BY CurrencyTypeOrder, Rank
GO

The core difference: the slow version uses SET ANSI_NULLS OFF, while the fast version uses SET ANSI_NULLS ON.

ANSI_NULLS Mechanism Detailed Explanation

The ANSI_NULLS setting affects how SQL Server handles NULL value comparisons:

When ANSI_NULLS is ON:

When ANSI_NULLS is OFF:

In our case study, the view contains conditions like (table.column IS NOT NULL), and different ANSI_NULLS settings cause the query optimizer to generate completely different execution plans.

Development Tool Default Setting Variations

The problem is further complicated by default setting differences across SQL Server tools:

This default setting variation explains why developers observe good performance during testing but experience performance degradation after deployment. Microsoft acknowledges this behavior in Knowledge Base article KB296769.

Solutions and Best Practices

Solution 1: Explicit ANSI_NULLS Setting

Explicitly specify ANSI_NULLS settings in stored procedure definitions:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE dbo.YourProcedure
    @Parameter data_type
AS
BEGIN
    -- Stored procedure logic
    SELECT * FROM YourTable WHERE Conditions
END
GO

Solution 2: Local Variables to Avoid Parameter Sniffing

While the primary cause in this case is ANSI_NULLS, parameter sniffing remains a common issue:

CREATE PROCEDURE GetOrders(@CustID varchar(20))
AS
BEGIN
    DECLARE @LocalCustID varchar(20)
    SET @LocalCustID = @CustID
    
    SELECT * 
    FROM orders
    WHERE customerid = @LocalCustID
END

Solution 3: Dynamic SQL and Execution Options

In certain scenarios, consider dynamic SQL or execution-time recompilation:

-- Dynamic SQL approach
CREATE PROCEDURE dbo.DynamicQuery
    @SessionGUID uniqueidentifier
AS
BEGIN
    DECLARE @SQL NVARCHAR(1000)
    SET @SQL = N'SELECT * FROM Report_Opener WHERE SessionGUID = @GUID ORDER BY CurrencyTypeOrder, Rank'
    
    EXEC sp_executesql @SQL, N'@GUID uniqueidentifier', @SessionGUID
END

-- Execution-time recompilation
EXEC YourProcedure @Parameter WITH RECOMPILE

Preventive Measures and Development Standards

  1. Unified Development Environment Settings: Ensure all development tools use identical ANSI settings
  2. Code Review Inclusion of SET Options: Verify stored procedure SET options during code reviews
  3. Automated Deployment Checks: Validate stored procedure settings in CI/CD pipelines
  4. Documentation Standards: Clearly define the ANSI standard version used by the team
  5. Comprehensive Performance Testing: Conduct performance tests under different settings

Technical Evolution and Compatibility Considerations

As SQL Server versions evolve, ANSI standard compatibility becomes increasingly important:

New projects should always use ANSI_NULLS ON to ensure forward compatibility.

Conclusion

The root causes of SQL Server stored procedure performance issues often lie in subtle details. While ANSI_NULLS setting differences may appear minor, they can cause significant execution plan variations. By understanding this mechanism, developers can:

Remember: in database performance optimization, the devil is in the details, and ANSI settings represent one of these critical details.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.