GaussDB数据库SQL系列:游标管理深度解析与实战指南

GaussDB数据库SQL系列:游标管理深度解析与实战指南

一、游标的核心价值

1.1 数据逐行处理能力
​​精细控制​​:逐行遍历结果集(如订单明细处理)
​​复杂业务逻辑​​:实现行级条件判断(如数据清洗规则)
​​状态保持​​:在事务中维持中间处理状态(如批次处理计数)
1.2 典型应用场景
场景 实现方式 性能特征
数据迁移 逐行转换后插入目标表 适合中小数据量
批次处理 每1000行提交事务 平衡内存与事务开销
动态计算 实时累加统计值 低延迟逐行处理

二、游标类型与适用场景

  1. 静态游标 vs 动态游标
-- 静态游标(绑定查询)
DECLARE cur_static CURSOR FOR 
SELECT * FROM orders WHERE status = 'pending';

-- 动态游标(参数化查询)
DECLARE cur_dynamic CURSOR (p_status VARCHAR) 
FOR SELECT * FROM orders WHERE status = p_status;
  1. 显式游标 vs 隐式游标
-- 显式游标管理
OPEN cur_orders;
LOOP
  FETCH cur_orders INTO order_rec;
  EXIT WHEN cur_orders%NOTFOUND;
  -- 处理逻辑...
END LOOP;
CLOSE cur_orders;

-- 隐式游标(FOR循环)
FOR order_rec IN (SELECT * FROM orders) LOOP
  -- 自动游标管理
END LOOP;
  1. 服务器端游标 vs 客户端游标
    特性 服务器端游标 客户端游标
    内存占用 数据库服务器内存 客户端内存
    网络传输 分批次拉取 一次性传输结果集
    适用场景 大数据量处理(>10万行) 中小数据量(<1万行)

三、游标管理全流程

  1. 基础操作模板
-- 声明阶段
DECLARE 
  cur_orders CURSOR FOR 
    SELECT order_id, amount FROM orders 
    WHERE create_time > '2023-01-01';
  
  v_order_id BIGINT;
  v_amount NUMERIC(10,2);
BEGIN
  -- 打开游标
  OPEN cur_orders;
  
  -- 循环获取
  LOOP
    FETCH cur_orders INTO v_order_id, v_amount;
    EXIT WHEN NOT FOUND;
    
    -- 业务处理(示例:金额转换)
    IF v_amount > 1000 THEN
      INSERT INTO large_orders VALUES (v_order_id, v_amount);
    END IF;
  END LOOP;
  
  -- 关闭游标
  CLOSE cur_orders;
END;
  1. 异常处理机制
DECLARE
  cur_data CURSOR FOR 
    SELECT * FROM sensitive_data;
  
  v_row RECORD;
BEGIN
  OPEN cur_data;
  BEGIN
    LOOP
      FETCH cur_data INTO v_row;
      EXIT WHEN NOT FOUND;
      -- 可能出错的敏感操作
      PERFORM process_sensitive_data(v_row);
    END LOOP;
  EXCEPTION 
    WHEN OTHERS THEN
      ROLLBACK;
      RAISE NOTICE 'Error at row: %', v_row.id;
  END;
  CLOSE cur_data;
END;

四、高级应用技巧

  1. 游标变量传递
-- 创建参数化游标函数
CREATE OR REPLACE FUNCTION get_orders_by_status(
  p_status VARCHAR
) RETURNS SETOF RECORD AS $$
DECLARE
  cur refcursor;
BEGIN
  OPEN cur FOR 
    SELECT * FROM orders WHERE status = p_status;
  RETURN NEXT cur;
END;
$$ LANGUAGE plpgsql;

-- 调用示例
SELECT * FROM get_orders_by_status('shipped');
  1. 批量获取优化
-- 使用ARRAY抓取(每次获取1000行)
DECLARE
  cur_ref refcursor;
  rows_arr RECORD[];
BEGIN
  OPEN cur_ref FOR SELECT * FROM large_table;
  
  LOOP
    FETCH cur_ref INTO rows_arr;
    EXIT WHEN rows_arr IS NULL;
    
    -- 批量处理(示例:更新状态)
    UPDATE target_table 
    SET processed = true 
    WHERE id = ANY(rows_arr.id_arr);
  END LOOP;
  
  CLOSE cur_ref;
END;

五、性能优化策略

  1. 游标参数调优
    参数 推荐值 效果
    cursor_tuple_fraction 0.1~0.3 减少预取数据量
    work_mem 4MB~64MB 提升排序/哈希性能
    max_parallel_workers 2~8 并行处理游标数据
  2. 分页游标实现
-- 基于OFFSET的分页(适合中小数据)
DECLARE
  cur_page CURSOR (p_offset INT, p_limit INT)
  FOR SELECT * FROM products 
      ORDER BY id 
      OFFSET p_offset LIMIT p_limit;
  
-- 基于ROW_NUMBER的分页(大数据推荐)
CREATE OR REPLACE FUNCTION get_paginated_data(
  p_page INT DEFAULT 1,
  p_size INT DEFAULT 100
) RETURNS TABLE(id BIGINT, name VARCHAR) AS $$
BEGIN
  RETURN QUERY 
  SELECT t.id, t.name
  FROM (
    SELECT *, ROW_NUMBER() OVER (ORDER BY create_time) AS rn
    FROM products
  ) t
  WHERE t.rn BETWEEN (p_page-1)*p_size+1 AND p_page*p_size;
END;
$$ LANGUAGE plpgsql;

六、避坑指南

  1. 游标泄漏检测
-- 查看未关闭游标
SELECT pid, usename, query 
FROM pg_stat_activity 
WHERE state = 'idle in transaction';

-- 自动关闭机制
CREATE OR REPLACE FUNCTION safe_cursor(
  p_query TEXT
) RETURNS VOID AS $$
DECLARE
  cur refcursor;
BEGIN
  OPEN cur FOR EXECUTE p_query;
  BEGIN
    -- 业务逻辑...
  EXCEPTION WHEN OTHERS THEN
    RAISE NOTICE 'Error occurred';
  END;
  CLOSE cur; -- 确保关闭
END;
$$ LANGUAGE plpgsql;
  1. 大数据量陷阱
-- 错误示例:一次性获取百万行
DECLARE 
  cur_big CURSOR FOR SELECT * FROM huge_table;
...
-- 正确做法:分批次处理
CREATE OR REPLACE FUNCTION process_big_data()
RETURNS VOID AS $$
DECLARE
  batch_size INT := 5000;
  total_rows INT;
BEGIN
  LOOP
    WITH chunk AS (
      SELECT * FROM huge_table 
      LIMIT batch_size OFFSET (total_rows := total_rows + batch_size)
    )
    INSERT INTO processed_data 
    SELECT * FROM chunk;
    
    EXIT WHEN NOT FOUND;
  END LOOP;
END;
$$ LANGUAGE plpgsql;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值