【问题标题】:Too Much Time to load Select Query加载选择查询的时间过多
【发布时间】:2018-01-17 09:53:52
【问题描述】:

我有一个查询,它需要大约 1 分 40 秒才能给出输出,有时需要超过 2 或 3 分钟。谁能帮忙告诉我为什么要花这么多时间?输出结果约为 409799 行。

Select 
 Distinct
 A.ID
 ,tracactionId Contracid
 ,Cancaldate 
,Suppliers
,Ct.Type "Contract Type"
,Sitename "Site Name" 
,St.Telephone "Site Telephone"
,Cc.Mobile
,At.Type "Action Type"
,Ms.Status "Order Status"
,Name Client
,Ass.Status
 ,Isnull(
     Case When Try_Parse(orderac As Numeric(10,2)) <= '60000' Then 'T3' 
     When Try_Parse(orderac As Numeric(10,2)) >= '60001' And 
    Try_Parse(orderac As Numeric(10,2)) <= '1000000' Then 'T2' 
     When Try_Parse(orderac As Numeric(10,2)) >= '1000001'  Then 'T1' End, 
   '-') "Consumption Order"
   ,Isnull(
     Case When Try_Parse(Replaceaq As Numeric(10,2)) <= '60000' Then 'T3' 
     When Try_Parse(Replaceaq As Numeric(10,2)) >= '60001' And 
  Try_Parse(Replaceaq As Numeric(10,2)) <= '1000000' Then 'T2' 
     When Try_Parse(Replaceaq As Numeric(10,2)) >= '1000001'  Then 'T1' End, 
   '-') "Consumption Replace"
  ,Case When Datepart(Day, Cancaldate ) > 21 And Cancaldate  < '9999-12-01'
  Then Substring(Datename(Month, Dateadd(Month, 1, Cancaldate )), 1, 3) + ' 
  ' + Datename(Year, Dateadd(Month, 1, Cancaldate ))
  Else Substring(Datename(Month, Cancaldate ), 1, 3) + ' ' + Datename(Year, 
  Cancaldate ) End As "Month Year"
   From return A
   Left  Hash Join Contract C On C.Contractid = A.contractid
                                                 And orderdate In (Select 
  Max(Aa.orderdate) From Return Aa Where Aa.Contractid = A.Contractid)
 Left  Hash Join Suppliers S On S.Suppliersid = C.Supplierid
  Left  Hash Join ordercontract Mc On Mc.Contractid = C.Contractid
 Left  Hash Join order M On M.orderid = Mc.orderid
 Left  Hash Join Contracttype Ct On C.Contracttypeid= Ct.ordercontracttypeid
 Left  Hash Join Site St On St.Siteid = C.Siteid
  Inner Hash Join ordersubtype Ast On Ast.ordersubtypeid = A.Aordersubtypeid
 Inner Hash Join ordertype At On At.ordertypeid = A.ordertypeid
 Left  Hash Join oderstatus Ms On Ms.orderstatusid = M.orderstatusid 
  Inner Hash Join Users U On U.Userid = A.userid
 Inner Hash Join orderstatus Ass On Ass.orderstatusid = A.orderstatusid
 Inner Hash Join product On A.productid = product.productid
 Inner Hash Join Contact Cc On product.Maincontactid = Cc.Contactid
 where  M.Meterstatusid <> 8 

这是创建非聚集索引的执行计划及其建议。

我是新手;请帮帮我。

/*
Missing Index Details from SQLQuery2.sql - 10.0.1.9.EnergyCRM_Main 
(adminlocal (84))
 The Query Processor estimates that implementing the following index could 
 improve the query cost by 15.558%.
 */

  /*
 USE [SAmpler]
   GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
 ON [dbo].[Action] ([orderID])
INCLUDE ([orderTypeID],[orderStatusID],[productID],[orderDate],
 [AssignedToUserID],[orderSubTypeID])
  GO
  */

【问题讨论】:

  • 看看执行计划,自己看看
  • 我们无法在您的数据库上运行您的查询,因此很难为您提供帮助。如果您需要帮助而不是在您的问题中添加实际的执行计划
  • 该查询看起来与 Ive read on some website 技术不匹配,但我会说你最好重写它从头开始并可能将查询专门化为较小的查询 - 而不是尝试修复它,尤其是通过简单地向数据库添加更多索引。
  • Distinct 子句也会变慢,在您的查询中是否需要 DISTINCT?
  • 是的@SandipPatel

标签: sql sql-server tsql sql-server-2016


【解决方案1】:

如果没有执行计划,这个问题真的很难回答。 查看代码我怀疑有几件事;

  • ISNULL 在索引列上使用时通常会损害性能,因为它禁止使用所述索引

  • 为什么所有连接都指定为哈希连接?在大多数情况下,最好让查询优化器决定哪个连接最快。

  • 我看到很多 try_parse,可能需要考虑预先检查/处理列并将它们设置为所需的数据类型。在这种情况下,您不必检查每一列是否是正确的数据类型。

【讨论】:

    【解决方案2】:

    只是想了解一下这个混乱

    您需要指明这些列来自哪些表
    不清楚所有的表都用过

    所有的 Try_Parse 都是一个问题

    表连接提示应该是最后的手段

    Select Distinct
           A.ID
         , tracactionId Contracid
         , Cancaldate 
         , Suppliers
         , Ct.Type "Contract Type"
         , Sitename "Site Name" 
         , St.Telephone "Site Telephone"
         , Cc.Mobile
         , At.Type "Action Type"
         , Ms.Status "Order Status"
         , Name Client
         , Ass.Status  
         , Isnull( Case When Try_Parse(orderac As Numeric(10,2)) <= '60000'   Then 'T3'
                        When Try_Parse(orderac As Numeric(10,2)) >= '60001' 
                         And Try_Parse(orderac As Numeric(10,2)) <= '1000000' Then 'T2' 
                        When Try_Parse(orderac As Numeric(10,2)) >= '1000001' Then 'T1' 
                   End
                   , '-'
                 ) "Consumption Order"
         , Isnull( Case When Try_Parse(Replaceaq As Numeric(10,2)) <= '60000' Then 'T3'
                        When Try_Parse(Replaceaq As Numeric(10,2)) >= '60001' 
                         And Try_Parse(Replaceaq As Numeric(10,2)) <= '1000000' Then 'T2' 
                        When Try_Parse(Replaceaq As Numeric(10,2)) >= '1000001' Then 'T1' 
                   End
                   , '-'
                 ) "Consumption Replace"
        , Case When Datepart(Day, Cancaldate ) > 21 And Cancaldate  < '9999-12-01'  
                    Then Substring(Datename(Month, Dateadd(Month, 1, Cancaldate )), 1, 3) 
                         + ' ' + Datename(Year, Dateadd(Month, 1, Cancaldate ))
               Else Substring(Datename(Month, Cancaldate ), 1, 3) 
                    + ' ' + Datename(Year, Cancaldate ) 
          End As "Month Year"
    From return A
    
    Inner Hash Join ordersubtype Ast On Ast.ordersubtypeid = A.Aordersubtypeid
    
    Inner Hash Join ordertype At     On At.ordertypeid     = A.ordertypeid 
    
    Inner Hash Join orderstatus Ass  On Ass.orderstatusid  = A.orderstatusid
    
    Inner Hash Join Users U On U.Userid                    = A.userid
    
    Inner Hash Join product On product.productid           = A.productid 
    Inner Hash Join Contact Cc On Cc.Contactid = product.Maincontactid 
    
    Left Hash Join Contract C 
      On C.Contractid                                      = A.contractid
     And orderdate In ( Select Max(Aa.orderdate) 
                        From Return Aa 
                        Where Aa.Contractid = A.Contractid 
                      )
    Left  Hash Join Suppliers S On S.Suppliersid               = C.Supplierid      
    Left  Hash Join Contracttype Ct On  Ct.ordercontracttypeid = C.Contracttypeid    
    Left  Hash Join Site St On St.Siteid                       = C.Siteid
    
    Left  Hash Join ordercontract Mc On Mc.Contractid          = C.Contractid  
    Left  Hash Join order M On M.orderid = Mc.orderid
    Left  Hash Join oderstatus Ms On Ms.orderstatusid = M.orderstatusid 
    
    where  M.Meterstatusid <> 8 
    

    【讨论】:

      【解决方案3】:

      这只是一个猜测,因为我们无法执行实际的查询。我最好的猜测是你所有的 ISNULL 都会影响性能。

      试试这个:

      Case When Try_Parse(orderac As Numeric(10,2)) <= '60000' Then 'T3' 
           When Try_Parse(orderac As Numeric(10,2)) >= '60001' And 
           Try_Parse(orderac As Numeric(10,2)) <= '1000000' Then 'T2' 
           When Try_Parse(orderac As Numeric(10,2)) >= '1000001'  Then 'T1' 
           ELSE '-' End AS "Consumption Order"
      

      【讨论】:

      • 不,同样需要时间,我添加了执行计划
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 2022-06-22
      • 2020-04-22
      • 2015-08-19
      相关资源
      最近更新 更多