而带有游标和动态 SQL 的循环不会终止



我喜欢编写一个过程,返回每个表的名称,其中有一行具有特定的 id。换句话说,这些表有一个列"id",它的类型是 varchar 并包含一个 uuid。在做了一些研究之后,我选择了以下方法(简化,专注于我无法解决/理解的问题(:

-- get a cursor for all foo table names that have an id column
DECLARE table_name_cursor CURSOR FOR
SELECT a.name
FROM sysobjects a, syscolumns b 
WHERE a.id = b.id 
AND a.name like 'Foo%'
AND b.name = 'id'
GO
-- define some variables
DECLARE @current_table_name VARCHAR(100)
DECLARE @id_found VARCHAR(100)
OPEN table_name_cursor
FETCH table_name_cursor INTO @current_table_name
WHILE @@SQLSTATUS = 0
BEGIN
EXEC ('SELECT @id_found = id from ' + @current_table_name + " where id = '@id_param'") -- @id_param will be passed with the procedure call
select @current_table_name  
FETCH table_name_cursor INTO @current_table_name
END
-- clean up resources
CLOSE table_name_cursor
DEALLOCATE table_name_cursor

当游标的大小相当小(在我的例子中为 ~20 个表(时,它按预期工作,但如果游标大小增长,则该过程永远不会终止。

这闻起来像是一个资源问题,但我在Sybase-Fu的白带无助于找到答案。

问题:为什么它停止处理"太多"游标行,有没有办法让它使用这种方法?

是否有另一种(更好(的方法来解决实际问题(在所有表上运行查询(?这不是为了生产,它只是某种开发/维护脚本。

围绕您的评论"它停止工作"有一些上下文可能会有所帮助,例如,proc 是否意外返回,proc 是否生成堆栈跟踪,它是否真的"停止"或"运行时间超过预期"?


一些基本的监控应该有助于弄清楚发生了什么:

  • sp_who是否将游标进程显示为被阻止(例如,被对正在查询的数据具有独占锁定的其他进程阻止(
  • master..monProcessWaits where SPID =<spid_of_cursor_process>进行定期查询,以显示任何等待时间较长的事件(例如,磁盘读取的等待时间长;网络写入的等待时间长(
  • master..{monProcessStatement|monProcessObject} where SPID = <spid_of_cursor_process>的定期查询是否显示 CPU/等待/逻辑读取/物理读取增加?

我猜您的一些 SELECT 正在针对id列上没有可用索引的庞大表运行,最终结果是某些 SELECT 正在运行昂贵(且缓慢(的表和/或索引扫描,可能不得不等待从磁盘中提取大量数据。

如果我的猜测是正确的,MDA 表应该显示不断增加的磁盘等待、逻辑/物理读取以及较小程度的 CPU。

此外,如果您看到大量逻辑/物理读取(指示表/索引扫描(,则当前运行的 SELECT 的查询计划应确认使用了表/索引扫描(因此无法在当前表的id列上查找/使用索引(。

对于较小/更快的测试运行,我猜您正在点击 a( 较小的表,其中表/索引扫描相对较快和/或 b(id列上具有可用索引的表(因此索引查找相对较快(。


其他需要考虑的事情...您使用什么应用程序进行 proc 调用?

我已经忘记了用户遇到一些的次数......我应该说"时髦"的问题吗...访问 ASE 时;问题通常追溯到前端/客户端应用程序的配置或编码问题。

在这些情况下,我建议用户通过isql命令行工具运行他们的查询和/或过程,看看他们是否得到相同的"时髦"结果;通常,isql命令行会话不会显示"时髦"行为,从而指出用户用于访问 ASE 的任何应用程序/工具存在问题。

注意:通过isql命令行工具,我的意思正是...命令行工具...不要与wisqldbisql或任何其他点击式GUI工具混淆(其中许多在某些情况下确实会导致一些"时髦"行为(。

注意:即使事实证明这是客户端问题(而不是ASE问题(,MDA表通常也可以查明这一点,例如,monProcessWaits在等待输出(到客户端(完成时可能会显示大量的等待时间;在这种情况下,sp_who也会显示状态为send sleep的SPID(即, ASE 正在等待客户端处理 ASE 发送到客户端的最后一个结果集(。

最新更新