此查询的性能令人难以置信

时间:2014-06-24 16:11:53

标签: sql sql-server performance

执行此查询时,我的性能非常低,

我看不出任何明显的东西,任何人都可以建议我通过它的最佳方式

CREATE TABLE #tmp_NominalPurchase (    
    NomCode varchar(16),    
    NomDesc varchar(61),    
    GoodsSold money 
) 

declare @Pos Int 
select @Pos = 1 
while @Pos <= (select max(dbo.fn_DCount(NValues,'~')) from pledger) 
begin   
    INSERT INTO #tmp_NominalPurchase    (NomCode, NomDesc, GoodsSold)    (       
    select 
        a.keyCode NomCode, 
        a.descr NomDesc,
        sum(convert(money, dbo.fn_Field(pl.NValues,'~', @Pos)   )) GoodsSold
    from pledger pl  
    inner join accts a 
        On  dbo.fn_Field(pl.NCodes,'~', @Pos) = a.keycode
        and (acctType='N' and pb='P' and category='cs')         
    where convert(datetime, pl.batch) >='2014-01-01' 
      and convert(datetime, pl.batch) <'2014-06-25'        
    group by a.keyCode, a.descr)   

    select @Pos = @Pos + 1 
end 

select o.* FROM
(
    select t.NomCode,
        t.NomDesc, 
        0 GoodsCost,
        0 GoodsDisc, 
        sum(t.GoodsSold) GoodsSold, 
        '24/06/2014 05:01:14 PM' as LocalDateAndTime 
    from #tmp_NominalPurchase t  
    group by 
        t.NomCode,
        t.NomDesc 
) o 
Order By o.NomCode Asc 

DROP TABLE #tmp_NominalPurchase

2 个答案:

答案 0 :(得分:1)

我看到的一个显而易见的事情是,在将where子句中的比较进行之前,您正在将pl.batch转换为字符串。这将打败任何可能阻止表扫描的索引。

您还在用户定义的函数fn_field上进行连接。不知道该功能的目的,我想知道这是否会产生问题。当我看到类似的东西时,我怀疑它就在那里,因为数据模式没有经过深思熟虑。

答案 1 :(得分:0)

没有重写的查询和性能大幅增加,这已经将查询运行时间从12秒减少到&lt; 1秒

  • 添加了一个获取计数的功能
  • SQL重写为使用计数

改进的SQL

SELECT dbo.fn_Field(pl.NValues,'~',1) AS [nVals1], dbo.fn_Field(pl.Ncodes,'~',1)  as [nCodes1], dbo.fn_Field(pl.NValues,'~',2)  as [nVals2], dbo.fn_Field(pl.Ncodes,'~',2)  as [nCodes2],
       'x' AS x INTO #tmp_NominalPurchase
FROM pledger pl
WHERE convert(datetime, pl.batch) >='2014-06-01'
  AND convert(datetime, pl.batch) <'2014-06-28'
  SELECT a.keycode AS NomCode,
         a.descr AS NomDesc,
         max(0) AS goodsCost,
         max(0) AS GoodsDisc,
         sum(CAST (NValue AS money)) AS GoodsSold ,
         '06/27/2014 11:44:47 AM' AS LocalDateAndTime
  FROM
    (SELECT [nVals1] AS NValue,[nCodes1] AS NCode
     FROM dbo.#tmp_NominalPurchase tnp
     UNION ALL SELECT [nVals2]AS NValue,[nCodes2] AS NCode
     FROM dbo.#tmp_NominalPurchase tnp) x
  INNER JOIN dbo.Accts a ON x.Ncode = a.keycode
  AND acctType='N'
  AND category='cs'
  AND pb='P'
GROUP BY a.keycode,
         a.descr
ORDER BY NomCode
DROP TABLE #tmp_NominalPurchase

获取计数的功能

Public Function getNCodeCount(ByVal sWhere) As Integer '00528591

 Dim Ds As DataSet
 Dim sqlSb As StringBuilder = New StringBuilder
 Dim nCodesCount As Integer = 0
 sqlSb.Append("SELECT isnull(max(dbo.fn_DCount(NValues,'~')),0) FROM PLEDGER PL with (nolock)" & sWhere)

 Ds = SqlConnect.SqlNet.OpenSQLdataset(sqlSb.ToString)
 If Ds Is Nothing Then GoTo report_failed
 If Ds.Tables.Count < 1 Then
  GoTo report_failed
 End If
 With Ds.Tables(0)
  For Each r In .Rows
    nCodesCount = r(0)
  Next
 End With
Return nCodesCount

Exit Function
 report_failed:
  Return 0

        '00528591 END

    End Function

构建SQL字符串并输出报告的功能

    Public Function LedgerNominalListingReportPurchase(ByVal DateFrom As String, ByVal DateTo As String, ByVal SortType As String, Optional ByVal DetailReport As Boolean = False, Optional ByVal NominalCode As String = "") As DataView 'L754303 (163.47)
            Dim sql As String = ""
            Dim gs As New GeneralSQL
            Dim aWhere As New ArrayList
            Dim sWhere As String = ""

            If IsDate(DateFrom) Then aWhere.Add("convert(datetime, pl.batch) >=" & gs.SqlDate(CDate(DateFrom)))
            If IsDate(DateTo) Then aWhere.Add("convert(datetime, pl.batch) <" & gs.SqlDate(CDate(DateTo).AddDays(1)))

            For Each s As String In aWhere
                If sWhere = "" Then
                    sWhere &= " where "
                Else
                    sWhere &= " and "
                End If
                sWhere &= s
            Next

            If Not DetailReport Then 'L754303 (163.47)

                'NEW SQL (FASTER) 00528591

                sql &= "SELECT max(dbo.fn_DCount(NValues,'~')) FROM PLEDGER"

                Dim nCodeCount As Integer = (getNCodeCount(sWhere))

                If nCodeCount = Nothing Or 0 Then

                    sql = "CREATE TABLE #tmp_NominalPurchase (NomCode varchar(16), NomDesc varchar(61), GoodsCost money, GoodsDisc money, GoodsSold money) SELECT * FROM #tmp_NominalPurchase DROP TABLE #tmp_NominalPurchase"

                Else

                    Dim qCount As Integer = 1


                    sql = "SELECT "

                    While qCount <= nCodeCount

                        sql &= "dbo.fn_Field(pl.NValues,'~'," + qCount.ToString
                        sql &= ") "
                        sql &= " as [nVals" + qCount.ToString
                        sql &= "], "

                        sql &= "dbo.fn_Field(pl.Ncodes,'~'," + qCount.ToString
                        sql &= ") "
                        sql &= " as [nCodes" + qCount.ToString
                        sql &= "], "

                        qCount += 1

                    End While

                    sql &= " 'x' as x "
                    sql &= "INTO  #tmp_NominalPurchase FROM pledger pl " & sWhere

                    sql &= "SELECT a.keycode as NomCode, a.descr as NomDesc,max(0) AS goodsCost,max(0) AS GoodsDisc, sum(cast (NValue AS money) ) AS GoodsSold "
                    sql &= String.Format(", '{0}' as LocalDateAndTime", Format(General.UserNow, vars.Ses.FmtDate & " " & "hh:mm:ss tt")) 'V759658 (163.31) - format the date column based on the CountryMode setting
                    sql &= " FROM ("

                    sql &= "SELECT [nVals1] AS NValue,[nCodes1] AS NCode FROM dbo.#tmp_NominalPurchase tnp "
                    qCount = 2

                    While qCount <= nCodeCount
                        sql &= " UNION all "
                        sql &= "SELECT [nVals" + qCount.ToString
                        sql &= "]AS NValue,[nCodes" + qCount.ToString
                        sql &= "] AS NCode FROM dbo.#tmp_NominalPurchase tnp"



                        qCount += 1

                    End While

                    sql &= ") x inner join dbo.Accts a on x.Ncode = a.keycode and acctType='N' AND category='cs'  AND pb='P' group by a.keycode,a.descr "
                    sql &= "ORDER BY " & SortType
                    sql &= " DROP TABLE #tmp_NominalPurchase"



                End If
            End If

 Return SqlConnect.SqlNet.OpenSQLdataset(sql).Tables(0).DefaultView '00529265 

End Function