重建索引脚本执行报错求助
重建索引脚本执行报错求助
看起来你的脚本遇到了两个核心问题:排序规则冲突和游标上下文的问题,我来一步步帮你解决:
错误原因分析
排序规则冲突:
你脚本里用了text类型的@Database变量,而且在拼接跨数据库的表名时,不同数据库的INFORMATION_SCHEMA.TABLES字段可能使用了不同的排序规则,导致字符串拼接时触发冲突报错。游标不存在报错:
通过EXEC (@cmd)创建的TableCursor是在独立的会话上下文里的,外面的CLOSE TableCursor和DEALLOCATE TableCursor根本访问不到这个游标,自然会报“游标不存在”的错误。
修改后的完整脚本
我调整了脚本的结构,解决了这两个问题:
DECLARE @Database NVARCHAR(128) -- 改成NVARCHAR(128),符合SQL Server数据库名的长度限制 DECLARE @cmd NVARCHAR(MAX) -- 改用MAX避免长度不够的问题 DECLARE DatabaseCursor CURSOR READ_ONLY FOR SELECT name FROM master.sys.databases WHERE name NOT IN ('master','msdb','tempdb','model','distribution') -- 排除系统库 --WHERE name IN ('DB1', 'DB2') -- 如需指定库,打开此注释并注释上面的排除条件 AND state = 0 -- 只处理在线数据库 AND is_in_standby = 0 -- 排除日志 shipping的只读库 ORDER BY name OPEN DatabaseCursor FETCH NEXT FROM DatabaseCursor INTO @Database WHILE @@FETCH_STATUS = 0 BEGIN -- 把处理单库所有表的逻辑全部放到动态SQL里,确保游标在同一个上下文 SET @cmd = N' DECLARE @Table NVARCHAR(255) DECLARE TableCursor CURSOR READ_ONLY FOR SELECT QUOTENAME(table_catalog) + ''.'' + QUOTENAME(table_schema) + ''.'' + QUOTENAME(table_name) FROM ' + QUOTENAME(@Database) + N'.INFORMATION_SCHEMA.TABLES WHERE table_type = ''BASE TABLE'' -- 指定统一排序规则,避免拼接冲突 COLLATE SQL_Latin1_General_CP1_CI_AS OPEN TableCursor FETCH NEXT FROM TableCursor INTO @Table WHILE @@FETCH_STATUS = 0 BEGIN BEGIN TRY DECLARE @RebuildCmd NVARCHAR(1000) SET @RebuildCmd = ''ALTER INDEX ALL ON '' + @Table + '' REBUILD'' -- PRINT @RebuildCmd -- 如需预览命令,打开此注释 EXEC (@RebuildCmd) END TRY BEGIN CATCH PRINT ''---'' PRINT @RebuildCmd PRINT ERROR_MESSAGE() PRINT ''---'' END CATCH FETCH NEXT FROM TableCursor INTO @Table END CLOSE TableCursor DEALLOCATE TableCursor ' EXEC sp_executesql @cmd -- 用sp_executesql比EXEC更安全,支持参数化 FETCH NEXT FROM DatabaseCursor INTO @Database END CLOSE DatabaseCursor DEALLOCATE DatabaseCursor
关键改动说明
- 把
@Database从text改成NVARCHAR(128):text是过时的大文本类型,数据库名最多128字符,用NVARCHAR更合适,也避免类型转换带来的排序规则问题。 - 将单库的表处理逻辑全部嵌入动态SQL:这样
TableCursor的声明、打开、关闭都在同一个会话上下文里,不会出现“游标不存在”的问题。 - 使用
QUOTENAME()函数拼接表名:比手动加[]更安全,能处理特殊字符的表名。 - 指定统一排序规则:在查询
INFORMATION_SCHEMA.TABLES时加上COLLATE,强制统一排序规则,解决拼接时的冲突。 - 改用
sp_executesql执行动态SQL:比直接EXEC (@cmd)更安全,也更利于性能优化。
如果不想用游标,其实还可以用基于集合的方式(比如临时表存储所有需要重建索引的表名),性能会更好,但上面的脚本已经完美解决你的现有问题啦~
备注:内容来源于stack exchange,提问作者Eng.Bassel
相关产品推荐
相关产品推荐

