繁体   English   中英

WHERE子句中的功能-处理不良性能

[英]Function in WHERE clause - dealing with poor performance

我有一张有超过100000条记录的大桌子。

我需要在用于评估totalSum的where子句中添加一个条件,并仅返回totalSum <> 0的记录。

这里使用联接和临时选项卡的吨,我不打算全部发布。

这是我的功能:

CREATE FUNCTION returnTotalSum(@clientID VARCHAR(20),@type INT,@currency VARCHAR(20),@date VARCHAR())

RETURNS INT
AS
BEGIN

DECLARE @totalSum BIGINT;

SET @totalSum = ( SELECT SUM (CONVERT(DECIMAL(18,4),P.iznos*(1-P.dp)/2))
                   FROM pts as p
                     INNER JOIN tippart t on p.tip = @type
                     INNER JOIN its i on p.partija = @clientID                      
                        WHERE p.currency = @currency and pts.dknizenja < @date
                GROUP BY p.partija )


RETURN @totalSum
END

我在这里使用它:(WHERE子句中的last AND)

... 
880001,
NULL, 
NULL,
NULL, 
NULL,
CONVERT(INT,REPLACE('2017.12.31','.',''))                 
            FROM ITS I WITH(NOLOCK)      
              JOIN TIPPART R WITH(NOLOCK) ON I.TIP = R.TIP       
              LEFT JOIN #UNPVT_TIPSTOPE_TS T (NOLOCK) ON I.KAMGRUPA = T.GRUPA AND I.TIP = T.TIP AND I.VALUTA = T.SIFVAL   
              LEFT JOIN #UNPVT_TIPSTOPE_TS T1 (NOLOCK) ON I.KAMGRUPA = T1.GRUPA AND I.TIP = T1.TIP AND I.VALUTA = T1.SIFVAL AND T.GRUPA IS NULL         
              LEFT JOIN #TMP_DODATNA_KS DS (NOLOCK) ON I.PARTIJA = DS.PARTIJA AND I.VALUTA = DS.SIFVAL AND I.KAMGRUPA = DS.GRUPA
              LEFT JOIN #NML_RATE N (NOLOCK)  ON I.TIP = N.TIP AND N.SIFVAL = I.VALUTA AND N.GRUPA = I.KAMGRUPA
             -- LEFT JOIN TIPSTOPE TS (NOLOCK) ON I.TIP = TS.TIP AND TS.GRUPA = I.KAMGRUPA AND TS.SIFVAL = I.VALUTA
              LEFT JOIN #NML_RATE_PERIOD NML (NOLOCK) ON I.TIP = NML.TIP AND I.VALUTA = NML.SIFVAL AND NML.GRUPA = I.KAMGRUPA AND NML.SIFVAL = I.VALUTA
             --WHERE NOT EXISTS (SELECT * FROM [dbo].[IC_INPT_AR_X_INT_RATE_SNPST] WHERE PARTIJA = I.PARTIJA AND VALUTA = I.VALUTA AND APP = 'ST')  
                  WHERE I.DOTVARANJE <= '2017.12.31'
                  AND (T.TIP IS NOT NULL 
                        OR T1.TIP IS NOT NULL 
                        OR DS.PARTIJA IS NOT NULL)
                        AND dbo.returnTotalSum(i.partija,r.tip,t.sifval,i.dotvaranje) <> 0

我认为这样做的问题是它必须遍历每条记录,进行比较,评估条件。 考虑到表中没有索引(由于没有特权,我无法添加索引),它倾向于永远运行。

我可以做些什么来改善此功能的性能,您对使用除功能之外的其他功能有什么建议吗?

您的函数应该转换为内联表值函数。

CREATE FUNCTION returnTotalSum
(
    @clientID VARCHAR(20)
    ,@type INT
    ,@currency VARCHAR(20)
    ,@date VARCHAR(10) --Don't store dates as strings...
)
RETURNS TABLE AS RETURN

SELECT TotalSum = SUM(CONVERT(DECIMAL(18,4), P.iznos * (1 - P.dp) / 2))
FROM pts as p
INNER JOIN tippart t on p.tip = @type
INNER JOIN its i on p.partija = @clientID                      
WHERE p.currency = @currency 
    and pts.dknizenja < @date
GROUP BY p.partija

在您的实现中,调用该函数作为过滤的一部分,可能会导致大量性能下降,这可能是由于多次索引扫描所致。

作为一般指导,如果您在没有此功能的情况下很好地实现此目标,则应该可以减少它。

如果没有数据结构和样本数据,将很难为您提供准确的解决方案。

请尝试以下代码:

    ... 
    880001,
    NULL, 
    NULL,
    NULL, 
    NULL,
    CONVERT(INT,REPLACE('2017.12.31','.','')) 
    FROM ITS I WITH(NOLOCK)      
        JOIN TIPPART R WITH(NOLOCK) ON I.TIP = R.TIP       
        LEFT JOIN #UNPVT_TIPSTOPE_TS T (NOLOCK) ON I.KAMGRUPA = T.GRUPA AND I.TIP = T.TIP AND I.VALUTA = T.SIFVAL   
        LEFT JOIN #UNPVT_TIPSTOPE_TS T1 (NOLOCK) ON I.KAMGRUPA = T1.GRUPA AND I.TIP = T1.TIP AND I.VALUTA = T1.SIFVAL AND T.GRUPA IS NULL 
        LEFT JOIN #TMP_DODATNA_KS DS (NOLOCK) ON I.PARTIJA = DS.PARTIJA AND I.VALUTA = DS.SIFVAL AND I.KAMGRUPA = DS.GRUPA
        LEFT JOIN #NML_RATE N (NOLOCK)  ON I.TIP = N.TIP AND N.SIFVAL = I.VALUTA AND N.GRUPA = I.KAMGRUPA
        -- LEFT JOIN TIPSTOPE TS (NOLOCK) ON I.TIP = TS.TIP AND TS.GRUPA = I.KAMGRUPA AND TS.SIFVAL = I.VALUTA
        LEFT JOIN #NML_RATE_PERIOD NML (NOLOCK) ON I.TIP = NML.TIP AND I.VALUTA = NML.SIFVAL AND NML.GRUPA = I.KAMGRUPA AND NML.SIFVAL = I.VALUTA
        --WHERE NOT EXISTS (SELECT * FROM [dbo].[IC_INPT_AR_X_INT_RATE_SNPST] WHERE PARTIJA = I.PARTIJA AND VALUTA = I.VALUTA AND APP = 'ST')  
    LEFT OUTER JOIN -- Added this join with same logic from function rather than calling a function. 
    (
        SELECT SUM (CONVERT(DECIMAL(18,4),P.iznos*(1-P.dp)/2)) TotalSum
    FROM pts as p
        INNER JOIN tippart t on p.tip = r.tip
        INNER JOIN its i on p.partija = i.partija     
        WHERE p.currency = t.sifval and pts.dknizenja < i.dotvaranje
        GROUP BY p.partija 
    ) SumTable
    WHERE I.DOTVARANJE <= '2017.12.31'
    AND (T.TIP IS NOT NULL 
        OR T1.TIP IS NOT NULL 
        OR DS.PARTIJA IS NOT NULL)
        AND SumTable.TotalSum <> 0  -- This is similar to your old logic where you were comparing with function output. 

查询说明:

  • 我在SumTable中添加了使用现有查询逻辑进行左外部联接的功能。
  • 由于额外的左外部p.partija具有p.partija ,因此它不会弄乱您的结果集。
  • 旧函数的所有输入均已替换为相关值,因为我们在此处进行内联查询。
  • 最后,改进了指示为性能SumTable.TotalSum罪魁祸首的where部分,并且不会调用函数,而是使用SumTable.TotalSum并将其与0进行比较。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM