TSQL:优化多个重复的子查询

时间:2014-07-17 11:57:36

标签: sql sql-server

我有这个基于日期/星期的表,我需要从中获取每个部门的数据行。 这些行包括多个星期(和/或句号),我试图找到最快的方法。 作为旁注,我使用动态SQL来创建查询,因为我的周和周期是可变的。

目前我的查询如下:

    SELECT tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id
, ISNULL (
    (SELECT SUM(employeesweek) * 40 
    FROM tblCAPACITY_PROJECT as vwCap
    INNER JOIN tblPROJECT as vwPro ON vwCap.fk_project_id = vwPro.id
        AND vwPro.active = 1 
        AND vwPro.capacityproject = 1       
    INNER JOIN tblPROJECT_COMPANY_DEPARTMENT as vwProCD on vwPro.id = vwProCD.fk_project_id
        AND vwProCD.fk_company_structure_instance_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_structure_instance_id 
        AND vwPro.status = tblPROJECT.status 
    WHERE vwProCD.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id 
    AND CAST(vwCap.year AS Varchar(4)) + vwCap.weeknumber BETWEEN 201425 AND 201436 
    ), 0) AS Total
, ISNULL ((
    SELECT SUM(employeesweek) 
    FROM tblCAPACITY_PROJECT as vwCap        
    INNER JOIN tblPROJECT as vwPro ON vwCap.fk_project_id = vwPro.id       
        AND vwPro.active = 1 
        AND vwPro.capacityproject = 1       
    INNER JOIN tblPROJECT_COMPANY_DEPARTMENT as vwProCD on vwPro.id = vwProCD.fk_project_id       
        AND vwProCD.fk_company_structure_instance_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_structure_instance_id 
        AND vwPro.status = tblPROJECT.status 
    WHERE vwProCD.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id 
    AND vwCap.Year = 2014 AND vwCap.Weeknumber = 25 
    ), 0) AS Week1
, ISNULL ((
    SELECT SUM(employeesweek) FROM tblCAPACITY_PROJECT as vwCap        
...
), 0) AS Week2
, ISNULL ((
    SELECT SUM(employeesweek) FROM tblCAPACITY_PROJECT as vwCap        
...
    ), 0) AS Week3
, ISNULL ((
    SELECT ROUND(SUM(employeesweek) / 4, 2,0) 
    FROM tblCAPACITY_PROJECT as vwCap           
    INNER JOIN tblPROJECT as vwPro ON vwCap.fk_project_id = vwPro.id       AND vwPro.active = 1 AND vwPro.capacityproject = 1       
    INNER JOIN tblPROJECT_COMPANY_DEPARTMENT as vwProCD on vwPro.id = vwProCD.fk_project_id       
    AND vwProCD.fk_company_structure_instance_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_structure_instance_id 
    AND vwPro.status = tblPROJECT.status 
    WHERE vwProCD.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id 
    AND vwCap.Year = 2014 AND vwCap.period = 08 
    ), 0) AS Period1
, ISNULL ((
    SELECT ROUND(SUM(employeesweek) / 4, 2,0) 
...
    AND vwCap.Year = 2014 AND vwCap.period = 09 
    ), 0) AS Period2
 FROM tblPROJECT      
 LEFT OUTER JOIN tblCAPACITY_PROJECT ON tblPROJECT.id = tblCAPACITY_PROJECT.fk_project_id     
 INNER JOIN tblCOMPANY ON tblPROJECT.fk_company_id = tblCOMPANY.id     
 INNER JOIN tblLOCATION ON tblPROJECT.fk_location_id = tblLOCATION.id     
 INNER JOIN vwCOMMANDERS ON tblPROJECT.fk_commander_id = vwCOMMANDERS.id     
 INNER JOIN tblPROJECT_COMPANY_DEPARTMENT ON tblPROJECT.id = tblPROJECT_COMPANY_DEPARTMENT.fk_project_id     
 INNER JOIN tblCOMPANY_DEPARTMENT ON tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id = tblCOMPANY_DEPARTMENT.id     
 INNER JOIN tblCOMPANY_STRUCTURE ON tblCOMPANY_DEPARTMENT.id = tblCOMPANY_STRUCTURE.fk_company_department_id     
    AND tblCOMPANY_STRUCTURE.[year] = 2014 
INNER JOIN tblCOMPANY_BUSINESSUNIT ON tblCOMPANY_STRUCTURE.fk_company_businessunit_id = tblCOMPANY_BUSINESSUNIT.id     
WHERE tblPROJECT.active = 1 AND tblPROJECT.capacityproject = 1     
    AND tblPROJECT_COMPANY_DEPARTMENT.fk_company_structure_instance_id = 38 
    AND tblPROJECT.status = 'D' 
    AND tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id = 956
GROUP BY tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id, tblCOMPANY_DEPARTMENT.name,     
    tblPROJECT_COMPANY_DEPARTMENT.fk_company_structure_instance_id, tblPROJECT.status

这给出了以下输出:

 fk_company_department_id Total Week1 Week2 Week3 Period1 Period2
 ----------------------------------------------------------------
                      956 24240    28    28    34    28,5   91,75

(我用......替换了一些重复的代码)

经过一番搜索,我发现将子查询转换为连接可能会有所帮助,所以我这样做了:

SELECT DISTINCT tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id, 
    tblCOMPANY_DEPARTMENT.name as companydepartmentname, 
    sTotal.total, sWeek1.Week1, sWeek2.Week2, sWeek3.Week3, 
    sPeriod1.Period1, sPeriod2.Period2
FROM tblPROJECT 
LEFT OUTER JOIN tblCAPACITY_PROJECT ON tblPROJECT.id = tblCAPACITY_PROJECT.fk_project_id 
INNER JOIN tblCOMPANY ON tblCOMPANY.id = tblPROJECT.fk_company_id 
INNER JOIN tblLOCATION ON tblPROJECT.fk_location_id = tblLOCATION.id 
INNER JOIN vwCOMMANDERS ON tblPROJECT.fk_commander_id = vwCOMMANDERS.id 
INNER JOIN tblPROJECT_COMPANY_DEPARTMENT ON tblPROJECT.id = tblPROJECT_COMPANY_DEPARTMENT.fk_project_id 
INNER JOIN tblCOMPANY_DEPARTMENT ON tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id = tblCOMPANY_DEPARTMENT.id 
INNER JOIN tblCOMPANY_STRUCTURE ON tblCOMPANY_DEPARTMENT.id = tblCOMPANY_STRUCTURE.fk_company_department_id 
    AND tblCOMPANY_STRUCTURE.[year] = 2014 
INNER JOIN tblCOMPANY_BUSINESSUNIT ON tblCOMPANY_STRUCTURE.fk_company_businessunit_id = tblCOMPANY_BUSINESSUNIT.id
INNER JOIN ( 
        SELECT ISNULL(SUM(employeesweek),0) * 40 Total, PCD1.fk_company_department_id 
        FROM tblPROJECT as P1 
        INNER JOIN tblPROJECT_COMPANY_DEPARTMENT as PCD1 on P1.id = PCD1.fk_project_id 
            AND PCD1.fk_company_structure_instance_id = 38 
            AND P1.active = 1 AND P1.capacityproject = 1 
            AND P1.status = 'D' AND PCD1.fk_company_department_id = 956 
        LEFT OUTER JOIN tblCAPACITY_PROJECT as CP1 ON CP1.fk_project_id = P1.id 
            AND CAST(CP1.Year AS Varchar(4)) + CP1.weeknumber BETWEEN 201425 AND 201436 
        GROUP BY PCD1.fk_company_department_id
        ) sTotal 
        ON sTotal.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id
INNER JOIN ( 
        SELECT ISNULL(SUM(employeesweek),0) Week1, PCD1.fk_company_department_id 
        FROM tblPROJECT as P1 INNER JOIN tblPROJECT_COMPANY_DEPARTMENT as PCD1 on P1.id = PCD1.fk_project_id 
            AND PCD1.fk_company_structure_instance_id = 38 
            AND P1.active = 1 AND P1.capacityproject = 1 
            AND P1.status = 'D' AND PCD1.fk_company_department_id = 956 
        LEFT OUTER JOIN tblCAPACITY_PROJECT as CP1 ON CP1.fk_project_id = P1.id 
            AND CP1.Year = 2014 AND CP1.Weeknumber = 25 
        GROUP BY PCD1.fk_company_department_id
        ) sWeek1 
        ON sWeek1.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id 
INNER JOIN ( 
        SELECT ISNULL(SUM(employeesweek),0) Week2, 
        ...
        ) sWeek2 
        ON sWeek2.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id 
INNER JOIN ( SELECT ISNULL(SUM(employeesweek),0) Week3, 
        ...
        ) sWeek3 
        ON sWeek3.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id
INNER JOIN ( 
        SELECT ROUND(ISNULL(SUM(employeesweek),0) / 4.0,2,0) Period1, PCD1.fk_company_department_id 
        FROM tblPROJECT as P1 INNER JOIN tblPROJECT_COMPANY_DEPARTMENT as PCD1 on P1.id = PCD1.fk_project_id 
        AND PCD1.fk_company_structure_instance_id = 38 
        AND P1.active = 1 AND P1.capacityproject = 1 AND P1.status = 'D' AND PCD1.fk_company_department_id = 956 
        LEFT OUTER JOIN tblCAPACITY_PROJECT as CP1 ON CP1.fk_project_id = P1.id 
        AND CP1.Year = 2014 AND CP1.period = 08 
        GROUP BY PCD1.fk_company_department_id
        ) sPeriod1 
        ON sPeriod1.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id 
INNER JOIN ( SELECT ROUND(ISNULL(SUM(employeesweek),0) / 4.0,2,0) Period2 
        ...
        ) sPeriod2 
        ON sPeriod2.fk_company_department_id = tblPROJECT_COMPANY_DEPARTMENT.fk_company_department_id

这看起来很有希望,但SQL客户端统计数据说不然...... 有没有人知道如何让它更快?

这是主表的创建:

CREATE TABLE [dbo].[tblCAPACITY_PROJECT](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [fk_project_id] [int] NOT NULL,
    [year] [int] NOT NULL,
    [period] [char](2) NOT NULL,
    [weeknumber] [char](2) NULL,
    [employeesweek] [float] NULL,
    [lastmodifyweek] [char](6) NULL,
    [fk_functiongroup_id] [int] NOT NULL,
    [lastmodifydate] [smalldatetime] NULL,
    [logfield] [varchar](8000) NULL,
 CONSTRAINT [PK_tblCAPACITY_PROJECT] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

SET ANSI_PADDING ON
GO

ALTER TABLE [dbo].[tblCAPACITY_PROJECT]  WITH CHECK ADD  CONSTRAINT [FK_tblCAPACITY_PROJECT_tblFUNCTIONGROUP] FOREIGN KEY([fk_functiongroup_id])
REFERENCES [dbo].[tblFUNCTIONGROUP] ([id])
GO

ALTER TABLE [dbo].[tblCAPACITY_PROJECT] CHECK CONSTRAINT [FK_tblCAPACITY_PROJECT_tblFUNCTIONGROUP]
GO

ALTER TABLE [dbo].[tblCAPACITY_PROJECT]  WITH NOCHECK ADD  CONSTRAINT [FK_tblCAPACITY_PROJECT_tblPROJECT] FOREIGN KEY([fk_project_id])
REFERENCES [dbo].[tblPROJECT] ([id])
GO

ALTER TABLE [dbo].[tblCAPACITY_PROJECT] CHECK CONSTRAINT [FK_tblCAPACITY_PROJECT_tblPROJECT]
GO

对于索引:

CREATE NONCLUSTERED INDEX [_dta_index_project_year_period] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_project_id] ASC,
    [year] ASC,
    [period] ASC
)
CREATE NONCLUSTERED INDEX [_dta_index_project_year_period_func] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_project_id] ASC,
    [year] ASC,
    [period] ASC,
    [fk_functiongroup_id] ASC
)
CREATE NONCLUSTERED INDEX [_dta_index_tblCAPACITY_PROJECT_project_id_weeknumber_year] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_project_id] ASC,
    [id] ASC,
    [weeknumber] ASC,
    [year] ASC
)
INCLUDE ( [period],
[employeesweek],
[lastmodifyweek],
[fk_functiongroup_id],
[lastmodifydate],
[logfield])
CREATE NONCLUSTERED INDEX [_dta_index_tblCAPACITY_PROJECT_project_year_week] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_project_id] ASC,
    [year] ASC,
    [weeknumber] ASC
)
INCLUDE ( [employeesweek],
[lastmodifyweek])
CREATE NONCLUSTERED INDEX [_dta_index_tblCAPACITY_PROJECT_project_year_week_functiongroup] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_project_id] ASC,
    [year] ASC,
    [weeknumber] ASC,
    [fk_functiongroup_id] ASC
)
INCLUDE ( [employeesweek],
[lastmodifyweek])
CREATE NONCLUSTERED INDEX [IX_fk_project_id] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_project_id] ASC
)
CREATE NONCLUSTERED INDEX [IX_tblCAPACITY_PROJECT_functiongroup] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [fk_functiongroup_id] ASC
)
CREATE NONCLUSTERED INDEX [IX_tblCAPACITY_PROJECT_weeknumber] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [weeknumber] ASC
)
CREATE NONCLUSTERED INDEX [IX_tblCAPACITY_PROJECT_year] ON [dbo].[tblCAPACITY_PROJECT] 
(
    [year] ASC
)
ALTER TABLE [dbo].[tblCAPACITY_PROJECT] ADD  CONSTRAINT [PK_tblCAPACITY_PROJECT] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)

0 个答案:

没有答案