在提高 SQL Query 的查询性能方面需要帮助
Posted
技术标签:
【中文标题】在提高 SQL Query 的查询性能方面需要帮助【英文标题】:Need help in improving query performance of SQL Query 【发布时间】:2021-06-10 11:54:57 【问题描述】:存储过程返回结果的时间过长,我想提高存储过程的性能。但我不确定问题到底发生在哪里。任何人都可以通过在 EXISTS 子句之后重写子查询来提供帮助。
仅供参考,这些表有数十万条记录
DECLARE @InvNo VARCHAR(MAX) = NULL,
SELECT @InvNo='123'
DECLARE @tblInv TABLE (RowID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED,
InvNo VARCHAR(MAX))
IF @InvNo IS NOT NULL
INSERT INTO @tblInv(InvNo)
SELECT value
FROM STRING_SPLIT(@InvNo,',')
select * from table1 t
where (@InvNo IS NULL
OR EXISTS (SELECT 1
FROM @tblInv i
INNER JOIN table2 inv
ON inv.inv_no = i.InvNo OR ISNULL(inv.alt_inv_no,'@@') = i.InvNo
INNER JOIN table3 isp
ON isp.inv_no = inv.inv_no
INNER JOIN table4 ic
ON ic.inv_no = inv.inv_no
WHERE isp.bl_no = t.bl_no
AND ic.cust_code = t.cust_code)
)
【问题讨论】:
我们仍然缺少我们在您的last question 中询问您的执行计划。另外,什么是“十万”? 问题可能是子查询中的OR
。
OR ISNULL(inv.alt_inv_no,'@@')
不会是 SARGable。使用IS NULL
和IS NOT NULL
正确处理您的NULL
值。你真的也需要EXISTS
中的所有JOIN
吗?
@Larnu 是的,我真的需要那些 JOINS。如果 InvNo 具有单个值或无值,则删除 OR 并添加一个额外的 EXISTS 似乎对我有用。对于逗号分隔的值,查询再次变慢了。。
请记住,我们大多数不是来自印度的人都不知道“lac”是什么。
【参考方案1】:
在没有任何其他信息的情况下,我建议将 exists
拆分为两个单独的条件:
select *
from table1 t
where @InvNo IS NULL OR
EXISTS (SELECT 1
FROM @tblInv i JOIN
table2 inv
ON inv.inv_no = i.InvNo JOIN
table3 isp
ON isp.inv_no = inv.inv_no JOIN
table4 ic
ON ic.inv_no = inv.inv_no
WHERE isp.bl_no = t.bl_no AND ic.cust_code = t.cust_code
) OR
EXISTS (SELECT 1
FROM @tblInv i JOIN
table2 inv
ON inv.alt_inv_no = i.InvNo JOIN
table3 isp
ON isp.inv_no = inv.inv_no JOIN
table4 ic
ON ic.inv_no = inv.inv_no
WHERE isp.bl_no = t.bl_no AND ic.cust_code = t.cust_code
);
OR
通常会扼杀JOIN
s 的性能。
然后确保您对所有 JOIN
键都有索引。
【讨论】:
谢谢你,戈登。你是个天才。你救了我。你是对的.. OR 是罪魁祸首。 :) 根据您的建议,性能会更好。但如果@InvNo 是逗号分隔值,则时间再次比原始查询长:( @ArpitaDutta 。 . . (1) 逗号分隔值通常只是一个问题,您不应该使用它们。 (2) 这回答了您在这里提出的问题。如果您有不同的问题,请提出一个新问题,并明确与该问题的不同之处。【参考方案2】:试试下面的查询, EXISTS 子句和 OR 子句的主要问题
由于 OR 子句中的条件之一是变量,我们可以将代码分为两部分,并且不需要在同一个查询中同时具有 IS NULL 和存在逻辑。 将exists子句中的连接列加载到临时表中会很好,与主表的内部连接可能会提供更好的性能。
SELECT @InvNo='123'
DECLARE @tblInv TABLE
(RowID INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, InvNo VARCHAR(MAX))
IF @InvNo IS NULL
BEGIN
select * from table1 t
END
ELSE
BEGIN
INSERT INTO @tblInv(InvNo)
SELECT value FROM STRING_SPLIT(@InvNo,',')
SELECT DISTINCT isp.bl_no,ic.cust_code INTO #T
FROM @tblInv i
INNER JOIN table2 inv
ON inv.inv_no = i.InvNo
INNER JOIN table3 isp
ON isp.inv_no = inv.inv_no
INNER JOIN table4 ic
ON ic.inv_no = inv.inv_no
UNION
SELECT DISTINCT isp.bl_no,ic.cust_code
FROM @tblInv i
INNER JOIN table2 inv
ON ISNULL(inv.alt_inv_no,'@@') = i.InvNo
INNER JOIN table3 isp
ON isp.inv_no = inv.inv_no
INNER JOIN table4 ic
ON ic.inv_no = inv.inv_no
select * from table1 t
INNER JOIN #T T2 ON T2.bl_no = t.bl_no AND T2.cust_code = t.cust_code
END
【讨论】:
感谢您的解决方案。但是我提到的查询只是包含许多其他查询的巨大存储过程的一部分。我不能像你建议的那样重写它。 :(以上是关于在提高 SQL Query 的查询性能方面需要帮助的主要内容,如果未能解决你的问题,请参考以下文章