【问题标题】:Finding total number of tables in union query在联合查询中查找表总数
【发布时间】:2017-04-12 06:27:02
【问题描述】:

我正在编写一个支持不同版本的 Sybase ASE 的代码。我正在使用联合查询,问题是不同版本的 Sybase ASE 在联合查询中支持不同数量的表。联合查询是动态的,将根据服务器中存在的数据库数量形成。

有什么方法可以找到特定 Sybase ASE 支持的最大表数?我现在知道的唯一解决方案是使用查询获取版本并从结果中挑选出版本号并在代码中相应地设置数字。但这不是一个很好的解决方案。我尝试检查是否有任何表存储了此值,但没有出现。任何人都可以为此提出任何解决方案吗?

【问题讨论】:

    标签: union sybase sap-ase


    【解决方案1】:

    由于这是您在此处重新发布的我的 SAP 响应,我将添加更多注释...

    • 这是一个概念证明,它回答了如何通过 T-SQL 获取信息的基本问题;假设任何真正希望实施该解决方案的人都会(最终)解决各种问题:开销/维护,例如...

    • 设置跟踪文件需要权限才能执行;哪些权限取决于您是否启用了细粒度权限(请参阅参考手册中的“设置跟踪文件”命令的注释);您需要决定是否/如何将权限授予其他用户

    • 虽然您确实不能重复使用跟踪文件,但您可以为跟踪文件所在的目录创建代理表,然后从目录中“删除”跟踪文件,例如:

    create proxy_table tracedir external directory at '/tmp' go delete tracedir where filename = 'my_serverlmiits' go

    • 如果您可以同时运行代理表解决方案的多个副本,那么您显然(?)需要确保为每个会话生成唯一的跟踪文件名称;虽然您可以通过将@@spid 附加到文件名来执行此操作,但您还可以添加登录名 (suser_name())、kpid(从 master..monProcess 中选择 KPID,其中 SPID = @@spid)等;您还需要确保这样的文件不存在在尝试创建它之前(例如,删除 tracedir where filename = '.....'; set tracefile ...)

    • 您的错误(从代理表中选择时)似乎与您在事务隔离级别 0 中运行的客户端应用程序有关(默认情况下,需要表上的唯一索引...不是您将针对指向 OS 文件的代理表完成);尝试将隔离级别设置为 1,或使用不默认为隔离级别 0 的客户端应用程序(例如,该示例使用基本 isql 命令行工具运行良好)

      李>
    • 如果要将此解决方案生产化,那么您可能希望分配一个单独的文件系统,以便任何“逃跑”跟踪会话不会填满重要的文件系统(例如,/var、/tmp , $SYBASE 等)

    • 同样从生产/安全的角度来看,我可能想研究在 DBA/系统 proc(创建以在创建者的权限下执行)中封装大量细节的可能性,以便确保开发人员不能在“错误”的目录中创建跟踪文件...并且不断地重复:控制/安全...


    然后……

    如果您打算这样做很多 ...并且您只对(联合)查询中的最大表数感兴趣,那么它可能会很多更容易构建一个静态的 if/then/else(或 case)表达式,它与您的 ASE 版本相匹配,可能的数字很少(参见 RobV 的帖子)。

    让我们面对现实吧,真的,真的,真的会构建一个包含超过 100 个表的查询,更不用说 500、1000 等等了? [你真的不想处理试图调整这样一个怪物! YIKES] 实际上,当您可以实现硬限制(例如,最多 100 个表)。

    我想得越多,作为一名 DBA,我将尽我所能确保您的应用程序不会创建一些怪物,数百个表查询最终导致我的数据服务器陷入困境,仅仅是因为开发人员无法提出更有效的解决方案。 [天堂禁止将这种类型的应用程序推广到普通用户社区,也就是说,我必须处理在我的数据服务器中运行的数十/数百个这个怪物的副本?!?!?!]

    【讨论】:

    • 非常感谢@markp 提供的信息。主要问题是我对数据库表和对其所做的更改的控制非常少,并且该应用程序不适用于特定的客户端。我们的应用程序中有很多旧代码,所以联合是我们现在唯一的选择。
    • 如果您正在谈论必须构建可变数量的 UNION 查询,请考虑:创建一个 #temp 表,在循环中将每个 UNION 查询作为一个独立的 INSERT/SELECT 填充 #temp表,然后在最后从#temp 表中选择最终结果集;在同一条线上还有其他选项,重点是您不必创建一些冒着生成讨厌的查询计划的风险的巨大的多联合查询。
    • 循环结构也无需担心查询中允许的最大表数;还是您正在创建一个包含 100 个表的查询?
    • 我们以前的方法是使用单个查询并获取记录,但性能很糟糕。我们也考虑过使用程序,但客户不同意对其数据库进行任何更改
    • 这听起来更像是一个(查询)设计问题;您的一项设计尝试遇到了查询中允许的表数的限制。由于有几种方法可以绕过这个限制(查询中的最大表数),我认为这个问题/线程几乎已经筋疲力尽,也许应该将重点/努力转向更大的图景......查询/过程(重新)设计
    【解决方案2】:

    您可以通过运行“dbcc serverlimits”获得此类限制(首先启用 traceflag 3604)。

    在 15.7 版之前,最大值为 256。 在 16.0 中,这被提高到 512。 在 16.0 SP01 中,此值再次提高到 1023。

    【讨论】:

    • 它只能在数据库服务器命令行上工作?那么是否 Sybase 没有任何存储这些信息的表?
    【解决方案3】:

    我建议您通过 SAP 支持打开一个案例/票证,以了解是否有任何系统表存储此信息。如果没有,我将实施您提到的繁琐解决方案,并将在 ASE15.7 日志中监控以下错误:

    CR 805525 -- If you exceed the number of tables in a UNION query you can get a signal 11 in ord_getrowbounds instead of an error message. 
    

    【讨论】:

    • 这个繁琐的解决方案的问题是我不知道客户将使用哪个版本。另一个问题是 ASE 16 子版本的数字不同。因此,将来如果数量增加,我将不得不再次更改代码。
    • 也许有一种方法可以在代码中引发并捕获“UNION 中的表太多”错误,然后调整代码...此外,如果 ASE 无法满足您的目标,也许是是时候重新审视/改变逻辑了。 SAP 支持和论坛怎么说?
    • 我在 SAP 社区得到了一个答案。他们建议的方法是首先将输出打印到文本文件,然后从文件中获取数据到代理表
    【解决方案4】:

    这是我从 SAP 社区得到的答案

    -- enable trace file for your spid
    set tracefile '/tmp/my_serverlimits' for @@spid
    go
    -- dump dbcc serverlimits output to your tracefile
    dbcc serverlimits
    go
    -- turn off tracing
    set tracefile off for @@spid
    go
    -- enable external file access:
    sp_configure 'enable file access',1
    go
    -- create proxy table pointing at the trace file
    create proxy_table dbcc_serverlimits external file at '/tmp/my_serverlimits'
    go
    -- find our column name ('record' of type varchar(255) in this case)
    sp_help dbcc_serverlimits
    go
    -- extract the desired row; store the 'record' value in a @variable
    -- and parse for the desired info ...
    select * from dbcc_serverlimits where lower(record) like '%union%'
    go
    
     record
     ------------------------------------------------------------------------
     Max number of user tables overall in a statement using UNIONs      : 512
    

    虽然这种方法存在一些问题。第一个问题是设置跟踪文件。我将主要每天使用此代码,并且在 Sybase 中,我认为我们无法删除或覆盖跟踪文件。其次是关于代理表。代理表将不得不被删除,但这可以通过以下代码来处理

    IF 
    exists (select 1 from 
    sysobjects where type = 'U' and name = 'dbcc_serverlimits')
    
    begin
    drop table 
    dbcc_serverlimits
    end
    go
    

    当从 dbcc_serverlimits 表中进行选择查询时,就会出现最后一个问题。它抛出以下错误

    无法执行语句。优化器找不到唯一的 可用于扫描表 'dbo.dbcc_serverlimits' 的索引 游标'jconnect_implicit_26'。 SQLCODE=311 服务器=************, Severity Level=16, State=2, Transaction State=1, Line=1 Line 24

    从 dbcc_serverlimits 中选择 *

    所有这些命令都必须写在程序中(这就是我的想法)。还有更优雅的解决方案吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-14
      • 2015-11-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多