Skip to content

SA0107 : Avoid using procedural logic with a cursor

Avoid using cursors with procedural logic; consider adopting a set-based approach for better performance and scalability.

Using cursors, while sometimes necessary, often leads to performance issues because they process one row at a time rather than set-based operations. This can be inefficient and slow, especially on large datasets.

For example:

-- Example of problematic cursor usage
DECLARE myCursor CURSOR FOR
SELECT ColumnName FROM TableName;
OPEN myCursor;
FETCH NEXT FROM myCursor INTO @Variable;
-- Additional cursor processing...
CLOSE myCursor;
DEALLOCATE myCursor;

This approach is problematic as it iterates through the result set row by row, potentially leading to high CPU usage and longer execution times compared to set-based operations.

  • Decreased performance due to row-by-row processing instead of leveraging SQL Server’s set-based processing capabilities.

  • Increased complexity and potential for errors in the code because cursors require explicit open, fetch, close, and deallocate operations.

Improve performance by replacing cursors with set-based operations when possible.

Follow these steps to address the issue:

1.Analyze the current cursor-based implementation to understand its purpose and the data transformation it performs. Examine the existing DECLARE , OPEN , FETCH , CLOSE , and DEALLOCATE statements to identify the target table and columns involved.

2.Conceptualize how the same data transformation can be achieved through a set-based approach. This often involves using SELECT , JOIN , WHERE , and other set-based SQL operations to achieve similar logic in a single query.

3.Refactor the cursor code into a set-based SQL query. This may include combining related tables using JOIN , filtering using WHERE clauses, and applying operations directly within the query.

4.Test the refactored query to ensure it produces the same results as the cursor-based implementation but with improved performance. Verify the logic and correctness of the output against expected results.

For example:

-- Example of set-based query replacing a cursor
SELECT ColumnName
FROM TableName
-- Additional set-based operations if necessary...

The rule has a Batch scope and is applied only on the SQL script.

Rule has no parameters.

The rule does not need Analysis Context or SQL Connection.

3 hours per issue.

Design Rules, Bugs

DECLARE CURSOR (Transact-SQL)

DECLARE vend_cursor CURSOR
FOR SELECT BusinessEntityID, Name, CreditRating FROM Purchasing.Vendor
OPEN vend_cursor
FETCH NEXT FROM vend_cursor;
  Message Line Column
1 SA0107 : Avoid using procedural logic with a cursor. 1 8

Analysis Rules