使用带有标量函数的 where 条件与使用交叉应用和表值函数的 where 条件
Posted
技术标签:
【中文标题】使用带有标量函数的 where 条件与使用交叉应用和表值函数的 where 条件【英文标题】:Using where condition with scalar functions vs where condition using cross apply & table valued function 【发布时间】:2016-05-06 00:16:02 【问题描述】:我正在尝试为我正在创建的存储过程确定最佳方法(最快!)。这是一个相当基本的存储过程,将用于比较两个系统之间的字段以确保数据完整性。起初我想使用临时表和添加索引,但我没有看到速度上有任何差异。然后在阅读了通过表值函数获得的性能提升后,我认为这将是一种可行的方法,但一些简单的测试并没有显示出任何改进。我什至担心优化查询的原因是,由于系统之间的字段长度不匹配(另一个问题),where 条件将使用许多标量函数,所以我假设在 where 子句中执行许多标量函数对性能。
这是方法#1:
SELECT
SLXID
FROM dbo.Salesforce_Contacts a WITH(NOLOCK)
JOIN _SLX_Contact b WITH(NOLOCK)
ON a.SLXID = b.Contactid
WHERE
a.IsDeleted = 0
AND
(
LEFT(a.FirstName, 32) != b.FirstName
AND LEFT(a.LastName, 32) != b.LastName
AND LEFT(a.Title, 64) != b.Title
AND dbo.GetSLXContactStatus(a.Contact_Status__c) != b.Status
)
这是使用表值函数的方法#2:
SELECT
a.SLXID
FROM dbo.Salesforce_Contacts a WITH(NOLOCK)
JOIN _SLX_Contact b WITH(NOLOCK)
ON a.SLXID = b.Contactid
CROSS APPLY
dbo._SFContact_Functions_TEMP(a.FirstName, a.LastName, a.Title, a.Contact_Status__c) CA
WHERE
a.IsDeleted = 0
AND
(
b.FirstName != CA.FirstName_32
AND b.LastName != CA.LastName_32 -- etc.
AND b.Title != CA.Title_64
AND b.Status != CA.Contact_Status
)
这是#2中使用的表值函数:
ALTER FUNCTION dbo._SFContact_Functions_TEMP
(
@FirstName VARCHAR(40)
,@LastName VARCHAR(80)
,@Title VARCHAR(128)
,@Status VARCHAR(20)
)
RETURNS TABLE
AS
RETURN
SELECT
LEFT(@FirstName, 32) FirstName_32
,LEFT(@LastName, 32) LastName_32
,LEFT(@Title, 64) Title_64
,dbo.GetSLXContactStatus(@Status) Contact_Status
GO
最后是执行计划(实际):
对于#1 对于 #2 非常感谢任何帮助或建议!
【问题讨论】:
我更喜欢没有自定义函数的版本;它似乎更简单。但是你的问题是什么? @GordonLinoff 我很可能是强迫症。查询需要 20-40 秒才能完成,这非常长(相对而言),所以我想尽可能加快速度。或许左函数等,所花费的时间是无法避免的? 【参考方案1】:第一种方法更好。
首先,您要做什么?数据库设计似乎是错误的。
这是一次性查询还是永久查询。
假设你正在尝试做的事情是正确的,那么 20-40 秒的时间要少得多。
还显示 dbo.GetSLXContactStatus(a.Contact_Status__c) 内部的内容。
可能一次这样尝试,
tABLE dbo.Salesforce_Contacts
cLUSTERED INDEX ON SLXID
Create non clusterindex on IsDeleted AND INCLUDE COLUMN(FirstName,LastName,Title)
tABLE dbo._SLX_Contact
cLUSTERED INDEX ON Contactid
;With CTE
(
SELECT SLXID ,LEFT(a.FirstName, 32) FirstName, LEFT(a.LastName, 32) LastName
, LEFT(a.Title, 64) Title
FROM dbo.Salesforce_Contacts a WITH(NOLOCK)
WHERE
a.IsDeleted = 0
)
select * from CTE
JOIN _SLX_Contact b WITH(NOLOCK)
ON a.SLXID = b.Contactid
WHERE
a.FirstName=! b.FirstName
AND (a.LastName != b.LastName
AND a.Title != b.Title
AND dbo.GetSLXContactStatus(a.Contact_Status__c) != b.Status-- EXPLAIN THIS
)
如果您有很多记录,那么您可以将 CTE 记录插入到具有适当索引的临时表中
【讨论】:
【参考方案2】:从提供的图片来看,性能和自动优化计划#1 和#2 几乎没有差异。 SSMS 会提示您一个额外的索引。如果 #1 和 #2 不同(几乎不可能),请分析它们。尝试添加提供的索引。分析计划的具体用途。
【讨论】:
以上是关于使用带有标量函数的 where 条件与使用交叉应用和表值函数的 where 条件的主要内容,如果未能解决你的问题,请参考以下文章
如何使用带有交叉应用的 SQL OPENJSON 函数测量 json 文件中数组内数组的长度