【问题标题】:SQL query more rows return shorterSQL查询更多行返回更短
【发布时间】:2017-08-22 01:53:23
【问题描述】:

我有一个报告查询:

select 
    hp.KOD, hp.AD, hp.HES_ID,
    sum(fs.BORC_TUTARI) B_T, 
    sum(fs.ALACAK_TUTARI) A_T,
    max(hp.UST_HESAP_ID) UST_HESAP_ID, 
    max(hp. ALT_HESAP_SAYISI) ALT_HESAP_SAYISI
from 
    W_HES_PLAN hp, FIS_SATIRLARI fs, FIS_BASLIGI FB, 
    (select h.HESAP_KODU HESKOD, FS.HESAP_ID, FS.FIS_ID
     from HESAP_PLANI H, FIS_SATIRLARI fs
     where H.HESAP_ID = FS.HESAP_ID       
     group by h.HESAP_KODU,FS.HESAP_ID, FS.FIS_ID) CC 
where 
    CC.HESKOD like HP.KOD+'%'
    and FB.FIS_ID = FS.FIS_ID
    and CC.HESAP_ID = fs.HESAP_ID 
    and CC.FIS_ID = FS.FIS_ID 
     --  and hp.KOD>='' and hp.KOD<='200'
group by 
    hp.KOD, hp.AD, hp.HES_ID
order by 
    HP.KOD

CC 表的子查询在 7 秒内返回 676.427 行,但所有查询在 23 分钟内返回 14.000 行。我无法理解。为什么更多行返回更短?有什么优化建议吗?

【问题讨论】:

  • 如果您需要性能方面的帮助,请提供子查询本身和整体查询的查询执行计划。此外,我建议删除隐式连接,这样很难判断您的表是如何连接的。
  • Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已替换为 ANSI 中的 proper ANSI JOIN 语法-92 SQL 标准(25 年前),不鼓励使用它
  • 从概念上讲,我不认为很难理解为什么整个查询需要更长的时间,即使它返回的行数更少。它依赖于内部查询,因此您希望它至少花费与内部查询一样长的时间。再加上你增加了外部东西的费用(包括like)。就开销而言,“加法”可能更像是乘法。当您在结果中使用聚合时,行数也无关紧要。如果不聚合有多少行?这是一个反问,你不必回答。
  • FIS_BASLIGI表的作用是什么?您可能将它用作过滤器,但如果不是,因为您没有从中返回任何内容并且没有出现在 where 子句中,您可能可以将其删除。

标签: sql sql-server sql-server-2008 optimization


【解决方案1】:

我怀疑性能问题是因为您仍在使用 ANSI-89 样式的连接,这给了您一个您不想要的交叉连接。这是您的查询转换为 ANSI-92 样式连接。因为你没有查看 W_HES_PLAN 和 FIS_SATIRLARI 的谓词,所以你有一个交叉连接。我有一种感觉,这不是你想要的。这会导致一些巨大的性能问题和很可能不正确的值。

select 
    hp.KOD
    , hp.AD
    , hp.HES_ID
    , sum(fs.BORC_TUTARI) as B_T
    , sum(fs.ALACAK_TUTARI) as A_T
    , max(hp.UST_HESAP_ID) as UST_HESAP_ID
    , max(hp. ALT_HESAP_SAYISI) as ALT_HESAP_SAYISI
from 
    W_HES_PLAN hp
    cross join FIS_SATIRLARI fs
    join FIS_BASLIGI FB on FB.FIS_ID = FS.FIS_ID
    join 
    (
        select h.HESAP_KODU HESKOD
            , FS.HESAP_ID
            , FS.FIS_ID
        from HESAP_PLANI H
        join FIS_SATIRLARI fs on H.HESAP_ID = FS.HESAP_ID       
        group by h.HESAP_KODU
            ,FS.HESAP_ID
            , FS.FIS_ID
    ) CC on CC.HESKOD like HP.KOD+'%'
        and CC.HESAP_ID = fs.HESAP_ID 
        and CC.FIS_ID = FS.FIS_ID 
     --  and hp.KOD>='' and hp.KOD<='200'
group by 
    hp.KOD
    , hp.AD
    , hp.HES_ID
order by 
    HP.KOD

【讨论】:

  • Like 可能很昂贵。您和@SeanLange 拥有CC.HESKOD like HP.KOD+'%' 的地方可能值得一试Left(CC.HESKOD,len(HP.KOD))=HP.KOD。我不会做出任何承诺,但这是一种有时对我有用的方法。
  • 谢谢肖恩,但没有任何改变。23 分钟后返回。@SteveLovell 我也尝试了你的建议。同时结果相同。
  • 如果您有幸让HP.KOD 始终具有相同的长度,您应该将该长度替换为我给出的LEFT 函数而不是计算它。如果时间允许,我会再看看这个。
  • 我认为你错过了我的观点。正是交叉连接导致您在此处出现性能问题。这可能需要改为左连接或内连接。而且你使用的 LIKE 很好,因为它是一个尾随通配符,所以它仍然是 sargable。
  • @SeanLange,我没有错过你的观点。我同意你的看法,但取决于查询的真正目的(我不知道),可能别无选择。我希望在其他地方找到边际收益。如果结果正确(正如您所说的似乎有问题),则可能需要临时表和/或查询计划以特定方式进行的提示。另外,我学到了一个新术语:'sargable'(我一开始以为你打错了),谢谢!
猜你喜欢
  • 1970-01-01
  • 2019-10-02
  • 2015-09-20
  • 2019-04-05
  • 2011-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多