SQL Server:将多个连接查询分解为较小的连接并创建一个函数

时间:2015-01-29 10:30:39

标签: sql-server tsql

我有一个包含多个连接的复杂查询,它在我的应用程序中运行多次。我想通过将此查询分解为函数内的较小部分来将此查询编写为函数。作为一个新手,我对SQL Server的了解有限。

以下是查询:

SELECT 
     ts.lable as label,
     ts.percentage as rate
FROM 
     TaxSet ts 
JOIN 
     UserInfo u ON u.userID = ? 
                AND u.countryID = ts.countryId 
                AND (ts.stateId IS NULL OR ts.stateId = 0 OR LEN(ts.stateId) < 1)
JOIN
     Users us ON u.userID = us.id
JOIN
     Users p ON us.parentID = p.id
             AND ts.ispID = p.id
JOIN
     ProductType pt ON ts.productTypeID = pt.id
WHERE 
     startDate <= getutcdate() 
     AND getutcdate() <= endDate 
     AND pt.identifier = ?
     AND ts.id NOT IN (SELECT eu.ispTaxSettingId 
                       FROM ExemptUsers eu 
                       WHERE eu.ExemptUserId = ?)

现在,如何通过将此查询分解为较小的查询来编写函数。

提前致谢。

2 个答案:

答案 0 :(得分:1)

请问您为什么要将其拆分为函数?我重新格式化了您的代码,并暂时将其放入存储过程中。我的想法是你要传递一个Identifier和UserID,它们是你查询的参数。

我修改了查询并删除了Not In语句。这已被u.id = eu.ExemptUserID上的LEFT JOIN替换为ExemptUsers,然后添加到WHERE子句以确保eu.ExemptUserID为NULL。这基本上是一种更清晰的说法&#34;如果表中存在userID,则ExemptUsers不会为该用户带回结果&#34;。

此外,我已将联接移至用户p,因为我无法以任何方式查看此内容,除非您想确保用户拥有父级?

 CREATE PROCEDURE wsp_StoredProcName 
(@UserID int,
@Identifier int)

AS

BEGIN


    SELECT 
        ts.lable as label,
        ts.percentage as rate
    FROM 
         TaxSet ts 
            INNER JOIN UserInfo u ON u.userID = ts.UserID 
                AND u.countryID = ts.countryId  
            INNER JOIN Users us on u.userID = us.id
            INNER JOIN ProductType pt on ts.productTypeID = pt.id
            LEFT JOIN ExemptUsers eu on u.id = eu.ExemptUserID
    WHERE 
         (
            ts.UserID = @UserID
            and pt.identifier = @Identifier
            and startDate <= getutcdate() 
            and getutcdate() <= endDate 
            AND eu.ExemptUserID IS NULL
            and 
            (
            ts.stateId is null or ts.stateId = 0 or len(ts.stateId) < 1
            )
        )

END

答案 1 :(得分:1)

毕竟你从TaxSet中选择必须满足某些条件:日期范围,状态,与特定用户及其父级的关系,与特定产品类型的关系以及特定豁免的不存在用户。因此,在整个查询过程中使用EXISTS和NOT EXISTS,以便向读者和dbms显示您想要实现的内容。查询越简单,优化器就越容易处理它。

select 
  ts.lable as label,
  ts.percentage as rate
from taxset ts 
where getutcdate() between ts.startdate and ts.enddate 
and (stateid is null or stateid between 0 and 9)
and exists 
(
  select *
  from users u
  join userinfo ui on ui.userid = u.id
  where u.id = ?
  and ui.countryid = ts.countryid
  and u.parentid = ts.ispid
)
and exists
(
  select * 
  from producttype pt 
  where pt.identifier = ?
  and pt.id = ts.producttypeid
)
and not exists
(
  select *
  from exemptusers eu 
  where eu.exemptuserid = ?
  and eu.isptaxsettingid = ts.id
);

正如其他人所提到的:当将查询拆分成较小的部分并分别执行时,它通常变慢而不是更快。这是因为dbms在内部以最有效的方式完成了这一操作。当然,有时dbms的优化器无法找到一个好的执行计划。您可能希望查看执行计划并检查是否认为该计划是合适的。