ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

第二章 SQL命令参考-FETCH:Greenplum 游标取数配置与验证

第二章 SQL命令参考-FETCH:Greenplum 游标取数配置与验证 1. Greenplum 里 FETCH 到底解决什么问题如果你在 Greenplum 里写过存储过程或者做过大批量数据导出大概率遇到过这种场景一张表几千万行直接SELECT *拉回来客户端内存直接爆掉或者网络传输卡到怀疑人生。这时候游标CURSOR就是那个“分批取数”的阀门而FETCH就是拧开阀门的动作。FETCH是 SQL 命令参考里专门用来从已声明游标中检索行的命令。它不负责创建游标也不负责关闭游标它只干一件事把游标当前指向的那一行或那几行拿出来。在 Greenplum 中游标位置只能向前移动不支持滚动游标所以FETCH的方向控制比标准 PostgreSQL 要收敛一些但核心用法完全一致。这篇文章面向的是已经在用 Greenplum 做数据处理、需要按批次读取结果集的开发或运维同学。我会把FETCH的语法骨架、游标声明配置、在 psql 里的验证动作以及几个容易踩的坑一次性讲清楚。你跟着操作就能在自己的库上跑通一套完整的“声明-取数-核对-关闭”流程。需要说明的是Greenplum 的FETCH和标准 SQL 的FETCH在嵌入式 SQL 里语义略有差异但在交互式使用场景下它返回的就是一个类似SELECT的结果集。这一点在后面的验证环节会体现得很明显。2. 前置准备连接方式与 TaoToken 接入配置在开始写FETCH之前得先有一个能连上 Greenplum 的客户端。你可以用psql也可以用任何支持 PostgreSQL 协议的驱动。如果你是通过 API 方式做模型辅助生成 SQL 或做代码补全可以先把 TaoToken 的接入配置准备好这样在写游标逻辑时能直接让模型帮你补全语法。TaoToken 的 API 地址是https://taotoken.net/api官网入口在https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content。如果你只是想在写 SQL 时有个对话助手帮你解释FETCH的参数可以直接用模型对话功能如果是长期做 Greenplum 相关的编码和 Agent 任务建议走 Coding Plan额度更稳。配置上你需要在客户端里设置两个东西一个是 API Key一个是 Base URL。API Key 在控制台的 API Keys 页面生成Base URL 填https://taotoken.net/api。如果你用的是 OpenAI 兼容的客户端直接把这两项填进去就行。这一步不是必须的但如果你想让模型帮你生成游标模板或者排查FETCH报错提前配好会省很多事。注意TaoToken 只是模型接入层不替代你的数据库客户端。Greenplum 的连接还是走你自己的psql或驱动两者不要混在一起理解。3. 可复制的 FETCH 语法骨架与游标声明3.1 完整语法结构FETCH的基本形式是这样的FETCH [ forward_direction { FROM | IN } ] cursorname其中forward_direction可以是空也可以是下面这些之一NEXT FIRST LAST ABSOLUTE count RELATIVE count count ALL FORWARD FORWARD count FORWARD ALL在 Greenplum 里你只能向前取数所以BACKWARD相关的方向是不支持的。FORWARD和NEXT等价FORWARD count和直接写count等价。3.2 游标声明与事务边界游标必须在事务里声明这是很多人第一次写会忘的地方。标准流程是BEGIN; DECLARE mycursor CURSOR FOR SELECT * FROM films; FETCH FORWARD 5 FROM mycursor; CLOSE mycursor; COMMIT;DECLARE负责定义游标并绑定查询FETCH负责取数CLOSE负责释放COMMIT结束事务。如果你在BEGIN之前就DECLAREGreenplum 会直接报错。3.3 方向参数对照表方向写法含义Greenplum 是否支持NEXT取下一行默认值支持FIRST取第一行仅第一次 FETCH 可用支持LAST取最后一行支持ABSOLUTE count取指定行只能向前支持RELATIVE count相对当前位置向前取支持count取接下来 count 行支持ALL取剩余所有行支持FORWARD同 NEXT支持FORWARD count向前取 count 行支持FORWARD ALL向前取所有剩余行支持BACKWARD向后取不支持FORWARD 0和RELATIVE 0是个特殊用法它们不移动游标只是重新获取当前行。如果游标已经在第一行之前或者最后一行之后这个操作不会返回任何行。3.4 一个可直接跑的模板假设你有一张films表结构里有code、title、did、date_prod、kind、len这些字段。下面这段可以直接复制到psql里执行BEGIN; DECLARE mycursor CURSOR FOR SELECT code, title, did, date_prod, kind, len FROM films ORDER BY code; FETCH FORWARD 5 FROM mycursor; CLOSE mycursor; COMMIT;执行完你会看到前 5 行数据以表格形式返回。psql不会显示FETCH 5这样的命令标签而是直接把结果集画出来这一点和文档里说的“命令标签在 psql 中不显示”是一致的。4. 执行取数与结果集核对4.1 分批取数的实际写法如果你要处理的数据量很大通常会写一个循环每次FETCH一批。在 PL/pgSQL 里可以这样DO $$ DECLARE cur CURSOR FOR SELECT code, title FROM films ORDER BY code; rec RECORD; batch_size INT : 100; fetched INT : 0; BEGIN OPEN cur; LOOP FETCH FORWARD batch_size FROM cur INTO rec; EXIT WHEN NOT FOUND; fetched : fetched 1; RAISE NOTICE 当前行: %, %, rec.code, rec.title; END LOOP; CLOSE cur; RAISE NOTICE 共处理 % 行, fetched; END $$;这里FETCH ... INTO是 PL/pgSQL 里的用法和交互式FETCH返回结果集不同它把行放进变量里。EXIT WHEN NOT FOUND是判断游标是否走到末尾的标准写法。4.2 核对结果集是否完整取完数之后怎么确认没有漏行一个简单办法是用COUNT(*)和游标取出的行数做对比-- 先看总行数 SELECT COUNT(*) FROM films; -- 再用游标取全部 BEGIN; DECLARE c CURSOR FOR SELECT * FROM films; FETCH ALL FROM c; CLOSE c; COMMIT;如果FETCH ALL返回的行数和COUNT(*)一致说明取数完整。注意FETCH ALL执行后游标会停在最后一行之后再执行FETCH不会返回任何行。4.3 用 MOVE 做位置校验MOVE和FETCH的区别是MOVE只移动游标位置不返回数据。你可以用它来验证游标位置BEGIN; DECLARE c CURSOR FOR SELECT * FROM films ORDER BY code; MOVE FORWARD 3 IN c; FETCH NEXT FROM c; CLOSE c; COMMIT;上面这段会跳过前 3 行然后取第 4 行。如果你把MOVE换成FETCH FORWARD 3效果是取回前 3 行并停在第 3 行再FETCH NEXT取第 4 行。两者最终取到的行是一样的区别在于中间有没有把数据传回来。4.4 成功执行的返回特征FETCH成功执行后命令标签是FETCH countcount是实际读取的行数可能是 0。在psql里你看到的是结果集在驱动里你可以通过rowcount拿到这个数字。如果count是 0说明游标已经越过了可用行范围位置停在第一行之前或最后一行之后。5. 本篇常见报错与排查5.1 报错cursor xxx does not exist这个通常是因为DECLARE和FETCH不在同一个事务里或者事务已经COMMIT了。游标的作用域是事务级的事务一结束游标就没了。解决办法是把DECLARE、FETCH、CLOSE放在同一个BEGIN ... COMMIT块里。5.2 报错DECLARE CURSOR can only be used in transaction blocksGreenplum 不允许在事务外声明游标。如果你在自动提交模式下直接写DECLARE就会看到这个报错。先执行BEGIN;再声明即可。5.3 报错cursor can only scan forward这是 Greenplum 和标准 PostgreSQL 的一个关键差异。Greenplum 不支持滚动游标所以任何试图向后移动的操作都会失败。如果你写了FETCH BACKWARD或者FETCH ABSOLUTE -1这类语法就会触发这个错误。检查你的方向参数确保只用了FORWARD、NEXT、FIRST、LAST、ABSOLUTE正数、RELATIVE正数这些向前方向。5.4 取数结果为空但表里有数据先确认游标位置。如果你之前已经FETCH ALL过游标停在最后一行之后再FETCH自然返回空。另外检查DECLARE里的SELECT是否带了WHERE条件把数据过滤掉了。可以用MOVE 0重新获取当前行来确认位置但注意MOVE 0在游标越界时也不会返回数据。5.5 性能问题ABSOLUTE 取数很慢文档里明确说了ABSOLUTE抓取不会比导航到该行更快底层实现必须遍历所有中间行。如果你要取第 10000 行用ABSOLUTE 10000和连续FETCH NEXT10000 次的代价差不多。大批量取数时优先用FETCH FORWARD count顺序读取不要用ABSOLUTE跳行。5.6 通过游标更新数据不支持Greenplum 不支持通过游标做UPDATE ... WHERE CURRENT OF。如果你需要更新得先FETCH出主键再用单独的UPDATE语句按主键更新。这一点在文档的 Notes 里也提到了不要在这上面浪费时间。6. 继续深入相关命令与工具链FETCH不是孤立存在的它和DECLARE、CLOSE、MOVE是一套组合拳。DECLARE定义游标MOVE调整位置不取数FETCH取数CLOSE释放资源。你在写存储过程时基本就是这四个命令来回用。如果你在写 SQL 的过程中需要快速查FETCH的参数含义或者想让模型帮你生成一个带异常处理的游标模板可以用 TaoToken 的模型对话功能把报错信息贴进去让它帮你分析。地址是https://taotoken.net/api模型对话入口在控制台里能找到。长期做 Greenplum 开发的话Coding Plan 更适合高频调用场景API Keys 页面可以管理你的密钥。接入文档里有完整的 Base URL 配置和鉴权说明遇到 401 或 404 先查文档里的请求示例。把FETCH的方向参数和事务边界这两点吃透Greenplum 游标取数基本就不会再卡住你了。
返回列表