在数据库里游标(Cursor)通常很慢,因为它本质是逐行、串行处理。优化思路只有一个核心:尽量少用、尽量用集合操作代替,如果一定要用,也要让它“跑得更快”。下面按常见问题 + 优化手段给你一个实用清单。
把游标逻辑改写成:
INSERT INTO … SELECTUPDATE … FROMDELETE … WHEREMERGE(SQL Server / Oracle)示例:
-- 用游标(慢)
DECLARE cur CURSOR FOR SELECT id FROM orders;
-- 循环处理...
-- 改成集合操作(快)
UPDATE orders
SET status = 'CLOSED'
WHERE status = 'PENDING';
✅ 这是性能提升最大的方式
❌ 错误:
SELECT * FROM orders
✅ 正确:
SELECT id, status FROM orders
原因:
加索引、加过滤条件:
DECLARE cur CURSOR FOR
SELECT id FROM orders
WHERE status = 'PENDING';
✅ 给 status 建索引:
CREATE INDEX idx_orders_status ON orders(status);
不同数据库写法不同,但原则一样:
DECLARE cur CURSOR FAST_FORWARD FOR
SELECT id FROM orders;
FAST_FORWARD ≈ 只读 + 只进(最快)
MySQL 游标天然只读、只进,不用额外设置
很多性能问题不是查询慢,而是资源没释放
CLOSE cur;
DEALLOCATE cur;
| 游标类型 | 性能 | 说明 |
|---|---|---|
| 只进(Forward Only) | ⭐⭐⭐⭐⭐ | 最快 |
| 静态(Static) | ⭐⭐⭐ | 拷贝数据 |
| 动态(Dynamic) | ⭐⭐ | 锁定 + 回滚 |
| 键集(Keyset) | ⭐⭐ | 中等 |
✅ 原则:能只进就只进
游标内部本质还是 SQL:
SELECT id FROM orders WHERE status = 'PENDING'
✅ 有索引 vs 没索引,性能差 10~100 倍
❌ 错误:
BEGIN TRAN
-- 游标循环 100 万次
COMMIT
✅ 正确:
SELECT id, ROW_NUMBER() OVER (ORDER BY id) rn
INTO #tmp
FROM orders;
DECLARE @i INT = 1;
WHILE @i <= (SELECT MAX(rn) FROM #tmp)
BEGIN
SELECT id FROM #tmp WHERE rn = @i;
SET @i += 1;
END
✅ 比游标快,可控性更强
你可以拿你的游标对照一下:
SELECT 需要的列WHERECLOSE / DEALLOCATE✅ 可以接受的情况:
❌ 不建议:
如果你愿意,可以把具体数据库(MySQL / SQL Server / Oracle / PostgreSQL)+ 游标代码贴出来,我可以直接帮你改到最优版本。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。