WHERE 子句中的函数 - 处理性能不佳
Function in WHERE clause - dealing with poor performance
我有一个很大的 table,有超过 100000 条记录。
I need to add one more condition in the where clause used to evalute the totalSum and return only records with the totalSum <>
0.
这里使用了大量的连接和临时表,我并不打算post全部使用。
这是我的函数:
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 子句中的最后一个 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
我假设这个问题是它必须遍历每条记录,比较,评估条件。
考虑到 table 中没有索引(我无法添加索引,因为我没有权限)它往往会永远 运行。
Is there anything I can do to improve the performance of this
function, do you have any suggestions on using something else beside
functions and what?
您的函数转换为内联 table 值函数应该接近于此。
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
在您的实现中调用函数作为过滤的一部分 where 导致巨大的性能消耗,这可能是由于多次索引扫描。
作为一般指导,如果您在没有该功能的情况下也能很好地实现这一点,您应该能够减少它。
没有数据结构和示例数据,很难给你准确的解决方案。
试试下面的代码:
...
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
分组,因此不会弄乱您的结果集。
- 您的旧函数的所有输入都已替换为相关值,因为我们在这里进行内联查询。
- 最后,where 部分被指出是性能消耗的罪魁祸首得到改进,不再调用函数,而是使用
SumTable.TotalSum
并将其与 0 进行比较。
我有一个很大的 table,有超过 100000 条记录。
I need to add one more condition in the where clause used to evalute the totalSum and return only records with the totalSum <> 0.
这里使用了大量的连接和临时表,我并不打算post全部使用。
这是我的函数:
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 子句中的最后一个 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
我假设这个问题是它必须遍历每条记录,比较,评估条件。 考虑到 table 中没有索引(我无法添加索引,因为我没有权限)它往往会永远 运行。
Is there anything I can do to improve the performance of this function, do you have any suggestions on using something else beside functions and what?
您的函数转换为内联 table 值函数应该接近于此。
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
在您的实现中调用函数作为过滤的一部分 where 导致巨大的性能消耗,这可能是由于多次索引扫描。
作为一般指导,如果您在没有该功能的情况下也能很好地实现这一点,您应该能够减少它。
没有数据结构和示例数据,很难给你准确的解决方案。
试试下面的代码:
...
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
分组,因此不会弄乱您的结果集。 - 您的旧函数的所有输入都已替换为相关值,因为我们在这里进行内联查询。
- 最后,where 部分被指出是性能消耗的罪魁祸首得到改进,不再调用函数,而是使用
SumTable.TotalSum
并将其与 0 进行比较。