如何优化这个永远需要的 sql 查询?
Posted
技术标签:
【中文标题】如何优化这个永远需要的 sql 查询?【英文标题】:How do I optimize this sql query that takes forever? 【发布时间】:2015-03-12 15:41:07 【问题描述】:我正在尝试优化此查询,因为它需要 30 秒才能执行:
SELECT
TOP 100 table1.*
FROM
table1 (NOLOCK)
INNER JOIN
DB1..table2 (NOLOCK)
ON DB1..table2.id = DB1..table1.id
INNER JOIN
DB1..table2_batch (NOLOCK)
ON DB1..table2_batch.table2_batch_id = DB1..table2.table2_batch_id
INNER JOIN
DB2..table4 (NOLOCK)
ON CASE
WHEN CHARINDEX(':',
table2_batch.reference_number,
3) > 3 THEN SUBSTRING(table2_batch.reference_number,
3,
CHARINDEX(':',
table2_batch.reference_number,
3) -3 )
ELSE
RIGHT(table2_batch.reference_number,
LEN(table2_batch.reference_number) -2)
end = Cast(table4.PurchaseOrderID as int) INNER JOIN
DB2..table3 (NOLOCK)
ON DB2..table3.key = DB2..table4.key
WHERE
table1.id IS NOT NULL
AND (
table1.id!=''
OR table1.id IS NULL
)
AND DB2..table3.AccountTypeID != 30000
AND CHARINDEX('O', DB1..table2_batch.reference_number) = 1
AND table1_id NOT IN (
select
lim.table1_id
from
link_table1_message as lim (nolock)
inner join
table1 as i (nolock)
on i.table1_id = lim.table1_id
where
lim.message_id >= 90
)
ORDER BY
last_hit DESC
【问题讨论】:
这个问题不是更适合代码审查吗? 瓶颈在 DB2..table4 连接上。当我取出那部分时,它的查询速度非常快......但我真的需要在那里加入以确保满足这种情况的适当条件。 问题本身有更多的上下文,这确实很适合Code Review。ON CASE WHEN...
joins 也不太好闻。你试过 CTE 吗?
@usr 什么时候有一个case when
和一个无用的cast
曾经对on
子句中的性能有益?
@Mat'sMug 谁知道加入是否重要?连接的表可能包含零行。 99.9999% 的时间可以花在其他地方。 没有人知道任何事情。 我已经调整了 100 多个查询,但我不知道这里有什么慢的地方。 你永远无法从查询中判断出来。
【参考方案1】:
基于this comment:
瓶颈在于 DB2..table4 连接。当我拿出那部分时,它的查询速度非常快......但我真的需要在那里加入以确保满足这种情况的适当条件。
这有点猜测,因为我们不知道涉及多少行,也不知道您的架构是什么样的,但是做一些假设,这可能会有所帮助:
INNER JOIN DB2..table4 (NOLOCK) ON CASE WHEN CHARINDEX(':', table2_batch.reference_number, 3) > 3 THEN SUBSTRING(table2_batch.reference_number, 3, CHARINDEX(':', table2_batch.reference_number, 3) -3 ) ELSE RIGHT(table2_batch.reference_number, LEN(table2_batch.reference_number) -2) end = Cast(table4.PurchaseOrderID as int)
我找到了join
的很多逻辑。
你有一个table2_batch
,它有一个reference_number
,它正在编码一个你最终需要提取并用于与table4.PurchaseOrderID
连接的值;我会先选择它:
with cteTable2 as (
select
table2_batch_id
,reference_number
,case when charindex(':',reference_number,3) > 3
then substring(reference_number,3,charindex(':',reference_number,3) - 3)
else right(reference_number,len(reference_number) - 2)
end PurchaseOrderID
from table2_batch
)
然后您可以在随后的 select
语句中将 cteTable2
视为一个完整的表,因此您可以使用 cteTable2
而不是加入 table2_batch
:
inner join DB2..table4 (NOLOCK)
on cteTable2.PurchaseOrderID = cast(table4.PurchaseOrderID as int)
...cast
真的需要吗?
【讨论】:
以上是关于如何优化这个永远需要的 sql 查询?的主要内容,如果未能解决你的问题,请参考以下文章