我目前工作的一个特别复杂的用例。下面简化:)

首先,客户端记录与服务的集合的多对一的关系,即,单个客户机可具有与其相关联的多个服务。

在我的触发,我写的是基于一定的标准将返回客户的ID查询。的标准如下,

  1. 如果至少一个服务是B型的,并且不存在A型的服务,返回ID
  2. 如果至少一个服务是C型的,并且没有B或A型的服务存在,返回ID
  3. 如果至少一个服务的类型是d,并且没有类型C或B或A存在的服务,回报ID
  4. 和我的当前的做法是形成一个类似于以下

    的查询
    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,情况因人而异。 : - )

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top