【问题标题】:Get schema of stored procedure which returned error获取返回错误的存储过程的架构
【发布时间】:2018-01-08 14:13:37
【问题描述】:

我有几个名称相同但架构不同的过程。当这些过程引发错误时,有可能在父过程(调用这些嵌套存储过程)中获取引发错误的过程的架构?例如,我可以从ERROR_PROCEDURE() 获取名称,但是否有一些选项可以获取 SCHEMA ?因为否则我不确定如果有很多同名的程序会引发错误。

我猜这个功能仍然缺失 https://connect.microsoft.com/SQLServer/feedback/details/124627/schema-not-reported-in-the-error-procedure-function

但是有一些解决方法吗?

【问题讨论】:

  • error_procedure() 文档页面中有一条关于此问题的评论,日期为 2017 年 5 月 25 日,距离 2008 年版本发布已经过去了 10 多年......

标签: sql-server-2008 tsql error-handling database-schema


【解决方案1】:

遗憾的是,对于 SQL-Server 中的此限制,没有 100% 的解决方法。
很遗憾 MSSQL 开发团队在十多年后没有纠正这个问题。
它应该像添加一个新函数一样简单,如 ERROR_ProcedureSchema()ERROR_PROCID()
这是 2005 年 5 月重新发布的请求此功能的帖子:
https://feedback.azure.com/forums/908035-sql-server/suggestions/32894584-schema-not-reported-in-the-error-procedure-functio

我更喜欢尽可能详细地记录我在自定义错误处理逻辑中捕获的异常。
这是我能找到的最好的模式名称:

DECLARE @Error_ProcSchemaName nVarChar(128)--Leave as Null if found in more than 1 Schema.
--Only Populate the @Error_ProcSchemaName if it Belongs to 1 Schema. - 04/08/2019 - MCR.
SELECT @Error_ProcSchemaName = S.name
  FROM sys.objects as O
  JOIN sys.schemas as S
    ON S.schema_id = O.schema_id
  JOIN
  (
    SELECT O.name[ObjectName], COUNT(*)[Occurrences]
      FROM sys.objects as O
     GROUP BY O.name
  ) AS Total
    ON Total.ObjectName = O.name
 WHERE O.name = ERROR_PROCEDURE()
   AND Total.Occurrences = 1

避免使用像OBJECT_SCHEMA_NAME(OBJECT_ID(ERROR_PROCEDURE())) 这样的字符串作为传递给OBJECT_ID() 的字符串应该已经包含架构(ERROR_PROCEDURE() 没有)。
否则它将默认为您的默认架构,(在大多数情况下)为dbo

运行此查询以查看跨架构重用的所有对象名称:

--View Object Names that Exist in Multiple Schemas: - 04/08/2019 - MCR.
SELECT S.name[SchemaName], O.name[ObjectName], Total.Occurrences,
       O.type[Type], O.type_desc[TypeDesc],
       O.object_id[ObjectID], O.principal_id[PrincipalID], O.parent_object_id[ParentID],
       O.is_ms_shipped[MS], O.create_date[Created], O.modify_date[Modified]
  FROM sys.objects as O
  JOIN sys.schemas as S
    ON S.schema_id = O.schema_id
  JOIN
  (
    SELECT O.name[ObjectName], COUNT(*)[Occurrences]
      FROM sys.objects as O
     GROUP BY O.name
  ) AS Total
    ON Total.ObjectName = O.name
 WHERE Total.Occurrences > 1
 ORDER BY [ObjectName], [SchemaName]

如果您只有几个重叠的对象(Sproc 和触发器),那么您可能不知道 Schema,因为它的来源可能很明显。
但是,如果不是这种情况,那么您可能需要:

  1. 更改存储过程/触发器的名称以使其唯一。
    这种选择违背了我的本质。
  2. 如果您使用高级错误处理,则使用 OBJECT_SCHEMA_NAME(@@PROCID) 手动添加 Sproc/Trigger 的架构 记录错误时在您的 Catch-Block 中。

注意:由于使用了 3rd Party Sproc,因此这些选项可能无法使用。
当使用多个具有相同名称的 Sproc/触发器进行故障排除时,您可以编写一个自定义 Wrapper-Sproc 来调用您的 3rd Party Sproc,然后记录您的 Wrapper 中抛出的任何异常,以准确了解是哪个 Schema/Sproc 引起的。

代码味道:
如果您有多个同名的 Sprocs/Triggers 分布在各种架构中
那么我将其称为“代码气味”。
意思是,您的架构存在缺陷。
您可能没有正确封装您的逻辑以供重用。
有时名称会与 Schema 重叠,但这应该很少见,而且只是巧合。

用于处理多租户/用户组访问的盗用架构:
如果您正在尝试多租户(将来自不同组织/用户组的数据存储在同一数据库中并防止他们看到彼此的信息)并在共享对象名称的每个模式中运行几乎相同的逻辑,那么这是一个设计问题。 如果用户将直接访问数据,您应该将数据保存在不同的数据库中
或者有一个TenantIDUserGroupID,当用户从自定义应用程序访问时,您总是在任何地方传递和过滤。

【讨论】:

    【解决方案2】:

    我能想到的一些可能的解决方案:

    • 重命名每个存储过程,以便它们在不同的架构中具有不同的名称。
    • 将一些调试输出添加到存储过程,以便在执行它们时,您可以看到发生错误时哪个在进行中。
    • 运行 SQL Profiler 以查看发生错误时调用的内容。

    但是,这些更多是从尝试解决您当前遇到的问题的角度来看的,而不是构建一些错误处理以用于将来可能的故障排除。您总是可以让这些存储过程将一些日志文件写入磁盘的某个位置,这样您就可以在遇到错误时查询这些日志。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 2014-05-15
      • 2017-03-16
      • 1970-01-01
      • 2019-01-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多