github

学习sql server 游标

在 SQL Server 中,游标是一种逐行处理数据的机制。它允许你像编程语言中的循环一样,一行一行地遍历查询结果集,并对每一行执行特定的操作。

核心概念:为什么需要游标?

SQL 是集合操作语言(一次处理一组数据),但在某些场景下,你需要逐行处理

  • 对每一行执行不同的复杂计算(例如,计算移动总和、基于上一行数据更新当前行)
  • 调用存储过程,且需要将每一行的列作为参数传入
  • 需要根据前一行数据的状态来决定当前行的操作

这时,游标就派上了用场。

SQL Server 游标的工作原理:五步生命周期

使用游标通常遵循以下五个标准步骤:

  1. DECLARE CURSOR(声明游标):定义游标所基于的 SELECT 查询语句。
  2. OPEN(打开游标):执行查询,将结果集填充到游标中。
  3. FETCH(提取行):从游标中获取一行数据到变量中。
  4. WHILE 循环处理:使用 @@FETCH_STATUS 系统变量判断是否还有数据(0 表示成功),在循环内处理业务逻辑。
  5. CLOSE & DEALLOCATE(关闭并释放):释放游标占用的资源。

一个完整的基础示例

假设有一个 Employees 表,我们要给每位员工加薪 10%。

-- 声明变量用于存储每行的数据
DECLARE @EmployeeID INT, @CurrentSalary DECIMAL(10,2);

-- 1. 声明游标
DECLARE SalaryCursor CURSOR FOR
SELECT EmployeeID, Salary FROM Employees;

-- 2. 打开游标
OPEN SalaryCursor;

-- 3. 获取第一行
FETCH NEXT FROM SalaryCursor INTO @EmployeeID, @CurrentSalary;

-- 4. 开始循环处理每一行
WHILE @@FETCH_STATUS = 0
BEGIN
    -- 业务逻辑:更新当前行的工资
    UPDATE Employees
    SET Salary = @CurrentSalary * 1.10
    WHERE EmployeeID = @EmployeeID;

    -- 获取下一行
    FETCH NEXT FROM SalaryCursor INTO @EmployeeID, @CurrentSalary;
END

-- 5. 关闭并释放游标
CLOSE SalaryCursor;
DEALLOCATE SalaryCursor;

游标的四种类型(性能差异巨大)

DECLARE CURSOR 时,你可以指定类型,直接影响性能和资源占用:

类型 特点 性能 典型场景
FAST_FORWARD 只读、只能向前滚动 最快(默认首选) 只需要单向遍历数据,不修改数据
READ_ONLY 只读,不能修改数据 很快 只需要读取数据做计算或展示
SCROLL 可前后滚动、可更新 较慢,占用较多资源 需要随机访问行(如向前/向后跳跃)
DYNAMIC 反映所有数据更改 最慢,资源开销大 需要看到其他用户对数据的实时修改

最佳实践与性能警告

  • 性能杀手:游标将基于集合的高效操作(一次处理几千行)变成逐行处理(几千次独立操作),可能导致性能下降几十甚至上百倍。在 SQL Server 中,循环是万恶之源
  • 优先使用基于集合的操作:能用一条 UPDATE 语句解决的问题,绝不用游标。例如上面的加薪示例,完全可以用 UPDATE Employees SET Salary = Salary * 1.10 一行代码完成,效率高得多。
  • 游标的替代方案
    • 使用窗口函数:如 ROW_NUMBER(), LAG(), LEAD() 可以替代许多需要逐行比较或累积计算的游标。
    • 使用递归 CTE:处理层次结构数据(如组织结构、菜单树)。
    • 使用临时表 + WHILE 循环:有时比游标效率稍高,但仍不如集合操作。

什么时候真的需要使用游标?

尽管有性能问题,少数场景游标仍然是合适的选择:

  • 调用需要逐行参数的存储过程:存储过程不接受集合参数,只能为每一行调用一次。
  • 复杂的逐行累计计算:当前行的值依赖于前一行的计算结果,且无法用 LAG/LEAD 表达(例如带有复杂业务规则的移动窗口)。
  • 分批处理大表:为了避免长事务阻塞或日志暴涨,可以用游标每次处理 1000 行,然后 COMMIT

总结

  • 记住:SQL 是基于集合的语言,优先思考“如何一次处理整个集合”。
  • 怀疑:当你觉得“可能需要游标”时,先停下来,搜索能否用 UPDATE窗口函数CTE 替代。
  • 最后手段:当确定无法避免时,使用 FAST_FORWARD 类型获得最佳性能,并确保游标循环内的操作尽量高效。
posted @ 2026-04-16 09:09  博讯科技工作室  阅读(3)  评论(0)    收藏  举报

赣州博讯科技工作室

©2019

回到顶部
回到底部
公众号 视博web工作室