Sybase 上的慢速 SQL 查询

Posted

技术标签:

【中文标题】Sybase 上的慢速 SQL 查询【英文标题】:Slow SQL query on Sybase 【发布时间】:2020-10-20 18:12:11 【问题描述】:

我正在尝试从数据库中提取信息。 Sybase ASE 16(虽然不确定 SP)。我自己没有直接访问数据库的权限,所以我必须请一位同事运行代码以提取我随后使用的信息。

首先,执行以下代码:

create table AAA (
    Operacion varchar(10) null,
    Actual smallint null,
    Castigado smallint null,
    RentasVar smallint null)
go

表索引是使用 bcp 从文本文件中填充的。 Actual、Castigado 和 RentasVar 为 0 或 1。

然后这段代码:

create view XXX as
    select Operacion, cast(convert(char(8), FecAplica, 112) as int) as FecAplica,
            IdPolizaSeg, SaldoInsSeg, CapitalSeg, InteresSeg,
            IvaSeg, MontoSeg, SegVenc
        from SEG_Vencim
        where Operacion in (
            select Operacion from AAA 
                where Actual=1)
go

create view YYY as
    select Operacion, IdTipoMov, DescMov, IdMoneda, StatuMov,
            cast(convert(char(8), FecMov, 112) as int) as FecMov,
            cast(convert(char(8), FecVencMov, 112) as int) as FecVencMov,
            cast(convert(char(8), FecPago, 112) as int) as FecPago,
            MontoMov, IvaMov, TotalMov, MontoDelPago
        from Movimientos
        where (Operacion in (
            select Operacion from AAA where Castigado=1))
                or (Operacion in (
                    select Operacion from AAA where Actual=1)
                        and (FecPago=null or FecPago>dateadd(dd, -30, current_date())))
go

Movimientos 中的字段操作是 varchar(10)。我无法修改此表。

发出 bcp 指令将 XXX 的内容复制到文本文件中。几秒钟后,任务完成,写了一个 aprox 文件。 140 MB。 发出 bcp 指令以将 YYY 的内容复制到文本文件中。该任务在将近 7 个小时后完成,编写了 aprox 的文件。 70 MB。

所以我的问题是第二条 bcp 指令耗时太长。 我读到 where 子句上的功能可能效率低下,所以我让我的同事再次尝试使用

and (FecPago=null or FecPago>='2020-09-30'))

而不是

and (FecPago=null or FecPago>dateadd(dd, -30, current_date())))

但它没有帮助。

AAA 有 80,000 到 90,000 条记录。把索引放在上面会有帮助吗? 我读到取消嵌套查询可能help,这对我有帮助吗?如果是这样,为什么第一个查询中的嵌套查询有效?

我无法自行运行测试,也无权访问执行计划。我意识到如果不提供其他信息,可能无法就此向我提供建议。

【问题讨论】:

这可能会超出 SO 支持的范围,例如,我们希望查看查询计划(即,set statement_cache off / set showplan on / set noexec on / go / select * from YYY / go - 这应该生成一个查询计划而不执行查询),来自sp_help/sp_spaceused,1 的所有相关表的输出,并且取决于查询计划的复杂性,可能是所有相关表的optdiag 输出;最简单/最快的解决方法可能是将 YYY 分成 3 个单独的查询(每个 `OR* 子句一个),看看是否有任何问题...... 如果您可以让 3x 单独查询“快速”运行,那么您可以尝试将 YYY 创建为 3x 单独查询的 3-way UNION(而不是 UNION ALL);虽然“取消嵌套”查询可能会有所帮助,但 ASE 16 的优化器应该足够聪明,可以为您展平(即“取消嵌套”)查询;我还建议在 FecPago 列上添加一个索引(并更新索引统计信息)如果不存在(至少与索引关联的统计信息可能有助于优化器) 我决定不使用 UNION,因为我宁愿只输入信息。如果必须写三次“选择...”部分,则分成三个单独的视图/文件。所以这个解决方案几乎等同于使用 UNION 而不是 OR,我不敢相信它有效!我的直觉仍然告诉我,我的原始查询应该稍微更有效率,但我知道直觉可能很危险。谢谢! 【参考方案1】:

我在 Sybase 方面没有太多经验,但在 MSSQL(它与 Sybase 的祖先相同)中,ORs 往往是性能杀手。将这些更改为 UNION 结构,正如 markp-fuso 通常建议的那样是一个好主意。

也就是说,我想知道将 OR 完全移动到子选择中会做什么:

create view YYY as
    select <your fields>
     from Movimientos
     where Operacion in (select Operacion 
                           from AAA 
                          where ( Castigado = 1)
                             or ( (Actual = 1 and (FecPago=null or FecPago > dateadd(dd, -30, current_date()))))
                        )

不确定优化器可能会对上述内容做什么。因此,我想知道如果我们首先强制 AAA 上的操作“实现”会发生什么……你能试一试吗?

create view YYY as
    select <your fields>
     from Movimientos m
     JOIN (SELECT DISTINCT Operacion 
             from AAA 
            where ( Castigado = 1)
               or ( (Actual = 1 and (FecPago=null or FecPago > dateadd(dd, -30, current_date()))))
          ) d
      ON d.Operacion = m.Operacion 
      

祝你好运。

PS:除了使用UNION 来摆脱ORs 之外,您还可以尝试使用WHERE EXISTS() 而不是IN() 构造。

【讨论】:

我决定不使用 UNION,因为我宁愿只输入信息。如果必须写三次“选择...”部分,则分成三个单独的视图/文件。所以这个解决方案几乎等同于使用 UNION 而不是 OR,我不敢相信它有效!我的直觉仍然告诉我,我的原始查询应该稍微更有效率,但我知道直觉可能很危险。谢谢! @JavierRivera 很高兴它有效,您最终使用的是什么版本? WHERE IN() 还是 JOIN (SELECT DISTINCT etc 一个? SQL 的“奇怪”之处在于,您几乎可以告诉系统 您想要什么,但对您想要的如何 没有太多把握;后端将解释您的查询,并根据许多因素找出获取数据的最有效方法。通常这很有效,有时您必须通过重新措辞来稍微调整一下您的请求。

以上是关于Sybase 上的慢速 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

在 JOIN 中重写慢速 SQL(子)查询

多表的慢速 SQL 查询

用于慢速 SQL 查询的 Django 日志过滤器

多键索引上的慢速范围查询

Sybase 运行从先前查询生成的 SQL

可能的sybase sql查询