如何跳过或消除最后一次加入查询

时间:2014-03-19 13:38:23

标签: sql-server

我有可选的参数化存储过程,但查询工作正常并且在表上有适当的索引。但是当最后一个参数传递时i:e部门代码和其他参数可以为NULL。查询需要很长时间而不会产生结果。时间不断增加但结果永远不会被检索。

有关如何跳过未使用的联接的任何建议,这与此方案中无关。

在这种情况下,我可以跳过下面的加入。

LEFT  JOIN EMPLOYEEADDRESS EA ON EA.EmployeeDetailsFK = ED.Id

任何建议如何避免此连接以使查询执行更快。

请在下面找到完整的查询

CREATE PROCEDURE prGetStudentData
(
@FirstName VARCHAR(50) = NULL,
@EmployeeCode VARCHAR(50) = NULL,
@Address VARCHAR(50) = NULL,
@DepartmentCode VARCHAR(50) = NULL
)
AS
BEGIN

SELECT E.* FROM EMPLOYEE E
INNER JOIN EMPLOYEEDETAILS ED ON ED.EmployeeFK = E.Id
LEFT  JOIN EMPLOYEEADDRESS EA ON EA.EmployeeDetailsFK = ED.Id
LEFT JOIN DEPARTMENT D ON D.Id = ED.DepartmentFK
WHERE (@FirstName IS NULL OR (E.FirstName = @FirstName) AND
 (@EmployeeCode IS NULL OR (ED.EmployeeCode = @EmployeeCode) AND
 (@Address IS NULL OR (EA.Address = @Address) AND
 (@DepartmentCode IS NULL OR (D.DepartmentCode = @DepartmentCode)
END

3 个答案:

答案 0 :(得分:1)

一个简单的答案是有条件地选择一个选择。

CREATE PROCEDURE prGetStudentData (
       @FirstName VARCHAR(50) = NULL,
       @EmployeeCode VARCHAR(50) = NULL,
       @Address VARCHAR(50) = NULL,
       @DepartmentCode VARCHAR(50) = NULL
     ) AS BEGIN

 IF @DepartmentCode IS NULL
   SELECT E.* 
     FROM            EMPLOYEE E
          INNER JOIN EMPLOYEEDETAILS ED ON ED.EmployeeFK = E.Id
          LEFT  JOIN EMPLOYEEADDRESS EA ON EA.EmployeeDetailsFK = ED.Id
          LEFT  JOIN DEPARTMENT D ON D.Id = ED.DepartmentFK
    WHERE (@FirstName IS NULL OR (E.FirstName = @FirstName) 
      AND (@EmployeeCode IS NULL OR (ED.EmployeeCode = @EmployeeCode) 
      AND (@Address IS NULL OR (EA.Address = @Address) 
      AND (@DepartmentCode IS NULL OR (D.DepartmentCode = @DepartmentCode)
 ELSE
   SELECT E.* 
     FROM            EMPLOYEE E
          INNER JOIN EMPLOYEEDETAILS ED ON ED.EmployeeFK = E.Id
          LEFT  JOIN EMPLOYEEADDRESS EA ON EA.EmployeeDetailsFK = ED.Id
    WHERE (@FirstName IS NULL OR (E.FirstName = @FirstName) 
      AND (@EmployeeCode IS NULL OR (ED.EmployeeCode = @EmployeeCode) 
      AND (@Address IS NULL OR (EA.Address = @Address) 

 END

答案 1 :(得分:1)

试试这个:

SELECT E.* FROM EMPLOYEE E
INNER JOIN EMPLOYEEDETAILS ED ON ED.EmployeeFK = E.Id
LEFT  JOIN EMPLOYEEADDRESS EA ON EA.EmployeeDetailsFK = ED.Id
LEFT JOIN DEPARTMENT D ON @DepartmentCode IS NOT NULL AND D.Id = ED.DepartmentFK
WHERE (@FirstName IS NULL OR (E.FirstName = @FirstName)) AND
 (@EmployeeCode IS NULL OR (ED.EmployeeCode = @EmployeeCode)) AND
 (@Address IS NULL OR (EA.Address = @Address)) AND
 (@DepartmentCode IS NULL OR (D.DepartmentCode = @DepartmentCode))

SELECT E.* FROM EMPLOYEE E
INNER JOIN EMPLOYEEDETAILS ED ON ED.EmployeeFK = E.Id
LEFT  JOIN EMPLOYEEADDRESS EA ON EA.EmployeeDetailsFK = ED.Id    
WHERE (@FirstName IS NULL OR (E.FirstName = @FirstName) AND
 (@EmployeeCode IS NULL OR (ED.EmployeeCode = @EmployeeCode) AND
 (@Address IS NULL OR (EA.Address = @Address) AND
 (@DepartmentCode IS NULL OR 
        EXISTS(SELECT * 
               FROM DEPARTMENT D 
               WHERE D.Id = ED.DepartmentFK 
               AND D.DepartmentCode = @DepartmentCode)
 )

答案 2 :(得分:1)

具有多个可选输入参数的存储过程可能会有问题。执行搜索功能的存储过程就是很好的例子。

在SQL中编写此类查询的一种常见方法是在(WHERE SomeColumn = @SomeVariable OR @SomeVariable IS NULL)形式的where子句中使用多个谓词。虽然这有效,但问题在于它的工作效率相当低。在大型表上,它可能导致查询性能非常差。

通常,更好的选择是通过sp_executesql使用参数化动态sql。查看Gail Shaw's Catch-All Queries博文。