了SQL子查询\功能性能
-
18-09-2019 - |
题
我目前工作的一个特别复杂的用例。下面简化:)
首先,客户端记录与服务的集合的多对一的关系,即,单个客户机可具有与其相关联的多个服务。
在我的触发,我写的是基于一定的标准将返回客户的ID查询。的标准如下,
- 如果至少一个服务是B型的,并且不存在A型的服务,返回ID
- 如果至少一个服务是C型的,并且没有B或A型的服务存在,返回ID
- 如果至少一个服务的类型是d,并且没有类型C或B或A存在的服务,回报ID 醇>
和我的当前的做法是形成一个类似于以下
的查询SELECT c.ClientId
FROM
Clients AS c
-- actually INNER JOIN is superfluous in this sample, but required for
-- other auxilliary criteria i have left out. illustrates relationship
-- between Clients and Services table
INNER JOIN Services AS s ON c.ClientId = s.ClientId
WHERE
-- has at least one service of type B, no A
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A'))) OR
-- has at least one service of type C, no B, no A
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'C')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A'))) OR
-- has at least one service of type D, no C, no B, no A
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'D')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'C')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A')))
其中[dbo].[Get_ServicesByClientIdAndType]
是,对于指定的客户机ID和服务类型返回相关联的服务的功能。类似
-- this query is actually significantly more complex than shown
-- below, but this illustrates use of parameters client id and
-- service type
SELECT s.ServiceType
FROM
Services AS s
WHERE
s.ClientId = @clientId AND
s.ServiceType = @serviceType
假设这是表达该用例最佳手段,将功能[dbo].[Get_ServicesByClientIdAndType]
子查询被缓存或不改变服务参数必须使用新的评价每个调用? [我正在调用这个东西好像9倍!运行SQL Server 2005]
我知道SQL Server 2005支持的一些子查询的优化,比如缓存的结果,但我不知道某些在什么情况下或如何形成我的子查询[或功能]这样的,我做的大多数SQL服务器的能力。
编辑:回顾我的标准之上,不能让一个唠叨的感觉的东西走得掉。我打得四处在我的脑海一些逻辑,以及与此想出了[简单得多配方
SELECT c.ClientId
FROM
Clients AS c
INNER JOIN Services AS s ON c.ClientId = s.ClientId
WHERE
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A')) AND
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) OR
EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'C')) OR
EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'D')))
基本上,不存在场景涉及B,这将导致排斥反应,类似地对于C和d,所以任何配置都是可接受的。我们只关心一个不存在于任何选择。 精氨酸!查理布朗!
留下两个表达式进行审查,我还是很欣赏有关SQL Server的性能WRT用户自定义函数的响应。
解决方案
我在写你的问题,并在此期间答案您已经改变了你的要求,但你不应该有任何问题,我的解决方案转化为您的特定需求..
不过,让我从一开始启动。
我敢肯定,SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A')
不是由服务器缓存反正。这并不是说聪明。)因此,它是在你的主查询计算多次
所以,你的第一个优化应该往那个方向发展。你应该减少次数时Get_ServicesByClientIdAndType
被调用。你可以在很多方面做到这一点。但是,一般的规则是,你应该计算该功能对所有客户的所有可能的结果。这些结果应该把一些temporarty表,否则将puted成一个虚拟表WHIS由SQL Server本身造成的。
当你有你的所有可能的结果,你只需用你的客户表加入他们的行列。但是,你只有加入他们的 ONCE
当然,很多事情和优化技巧取决于你的真实的例子。在这个例子中你给,甚至有没有必要使用Get_ServicesByClientIdAndType
。
为什么就不能加入这两个表并对其进行一些计算?
在这个查询请看:
SELECT A.* FROM
(
SELECT C.ClientID,
SUM(CASE(S.ServiceType) WHEN 'A' THEN 1 ELSE 0 END) AS ServiceA,
SUM(CASE(S.ServiceType) WHEN 'B' THEN 1 ELSE 0 END) AS ServiceB,
SUM(CASE(S.ServiceType) WHEN 'C' THEN 1 ELSE 0 END) AS ServiceC,
SUM(CASE(S.ServiceType) WHEN 'D' THEN 1 ELSE 0 END) AS ServiceD
FROM Clients AS C
INNER JOIN Services AS s ON c.ClientId = s.ClientId
GROUP BY C.ClientID
) A
WHERE ((A.ServiceB > 0) AND (A.ServiceA = 0))
OR ((A.ServiceC > 0) AND (A.ServiceA = 0) AND (A.ServiceB = 0))
OR ((A.ServiceD > 0) AND (A.ServiceA = 0) AND (A.ServiceB = 0) AND (A.ServiceC = 0))
在内部查询我们联接表。我们扔掉的功能,因为我们不需要它。相反,我们计算的为每一个客户不同的服务的数量。接下来在内部查询结果我们实现您的条件。我们只是检查的给定服务在particual集的发生。
其结果是这样的:
ClientID ServiceA ServiceB ServiceC ServiceD
-------- -------- -------- -------- --------
26915 0 4 2 2
26917 0 0 1 1
26921 0 3 2 3
26927 0 4 2 4
当然,你可以剥去服务列的最终结果。我已经包括了他们,因为我喜欢这样;-),它允许检查,如果查询工作正常。 你甚至可以编写一个查询,其将不计算给定服务类型的数量对于一个给定的客户端。它甚至会更快的工作,给你正确的结果。
此外,如果你真的需要你的功能,为什么不改变其实现的方式,该函数将返回后ID第一succesfull加入?它将为您节省大量的时间。
但是,只有你知道的大局观,因此所有我写到这里可能是垃圾; - )
无论如何,我希望我帮你以某种方式。
其他提示
这是SQL服务器的参数值的每一种组合调用你的函数Get_ServicesByClientIdAndType一次,但我猜想,在客户表中的每一行。你有值的三种组合,所以在客户端表100行,你可能会看到功能的300元话费。
但有信心,请在SQL Server Management Studio中的查询和选择“显示执行计划”切换。这样,你可以很容易地检测,你的查询中消耗优化的那部分最多的资源和conentrate。
有一点要记住的是避免“NOT”如果可能的话。 “NOT”非优化搜索,它将不能够采取索引全部优势。乍一看,我没有看到一个方法来重写它,以避免不表达,但。 FWIW,情况因人而异。 : - )