由于计算缓慢的SQL Server查询?

时间:2013-11-08 16:53:44

标签: asp.net sql sql-server timeout

我负责旧的时间记录系统,该系统是使用ADO.Net 2.0以ASP.net Web Forms编写的,用于持久化。

基本上,系统允许用户添加他们正在进行的工作的详细信息,为完成工作分配的工作小时数以及他们迄今为止在工作上花费的时间。

系统还有一个报告工具,其中包含基于SQL查询的报告。最近我注意到许多从系统运行的报告执行起来很慢。该数据库有大约11个表,并且它不存储太多数据。任何一个表都拥有27,000条记录,其中大部分表格远低于1,500条记录。

我不认为这个问题与大量数据有关,我认为这更多地与构造不良的SQL查询有关,甚至可能与数据库设计相同。

例如,有类似于此

的查询
@start_date datetime, 
@end_date datetime,
@org_id int 

select distinct t1.timesheet_id, 
                t1.proposal_job_ref, 
                t1.work_date AS [Work Date], 
                consultant.consultant_fname + ' ' + consultant.consultant_lname AS [Person], 
                proposal.proposal_title AS [Work Title], 
                t1.timesheet_time AS [Hours],

--GET TOTAL DAYS ASSIGNED TO PROPOSAL
(select sum(proposal_time_assigned.days_assigned)-- * 8.0) 
from proposal_time_assigned
where proposal_time_assigned.proposal_ref_code = t1.proposal_job_ref ) 
as [Total Days Assigned],


--GET TOTAL DAYS SPENT ON THE PROPOSAL SINCE 1ST APRIL 2013 
(select isnull(sum(t2.timesheet_time / 8.0), '0') 
from timesheet_entries t2 
where t2.proposal_job_ref = t1.proposal_job_ref 
and t2.work_date <= t1.work_date 
and t2.work_date >= '01/04/2013' ) 
as [Days Spent Since 1st April 2013],

--GET TOTAL DAYS REMAINING ON THE PROPOSAL 
(select sum(proposal_time_assigned.days_assigned) 
from proposal_time_assigned 
where proposal_time_assigned.proposal_ref_code = t1.proposal_job_ref )
- 
(select sum(t2.timesheet_time / 8.0) 
from timesheet_entries t2 
where t2.proposal_job_ref = t1.proposal_job_ref 
and t2.work_date <= t1.work_date
 ) as [Total Days Remaining]

from timesheet_entries t1, 
consultant, 
proposal, 
proposal_time_assigned 

where (proposal_time_assigned.consultant_id = consultant.consultant_id)
     and (t1.proposal_job_ref = proposal.proposal_ref_code) 
     and (proposal_time_assigned.proposal_ref_code = t1.proposal_job_ref)
     and (t1.code_id = @org_id) and (t1.work_date >= @start_date) and (t1.work_date <= @end_date) 
    and (t1.proposal_job_ref <> '0')

order by 2, 3

预计会返回报告数据。我甚至不确定是否有人可以跟踪上面的查询中发生的事情,但基本上有相当多的计算发生,即划分,乘法,减法。我猜这是减缓sql查询的原因。

我想我的问题是,任何人都可以对上面的查询有足够的认识,甚至建议如何加快它。

此外,是否应该在sql查询中执行上述计算?或者这应该在代码中完成吗?

任何帮助都会非常感谢这个。

感谢。

3 个答案:

答案 0 :(得分:1)

我在您的查询中看到的问题是:

1&GT;没有为表提供别名。 2 - ;使用子查询(执行成本消耗)而不是WITH子句。

如果我写你的查询,它将如下所示:

select distinct t1.timesheet_id, 
                t1.proposal_job_ref, 
                t1.work_date AS [Work Date], 
                c1.consultant_fname + ' ' + c1.consultant_lname AS [Person], 
                p1.proposal_title AS [Work Title], 
                t1.timesheet_time AS [Hours],

--GET TOTAL DAYS ASSIGNED TO PROPOSAL
(select sum(pta2.days_assigned)-- * 8.0) 
from proposal_time_assigned pta2
where pta2.proposal_ref_code = t1.proposal_job_ref ) 
as [Total Days Assigned],


--GET TOTAL DAYS SPENT ON THE PROPOSAL SINCE 1ST APRIL 2013 
(select isnull(sum(t2.timesheet_time / 8.0), 0) 
from timesheet_entries t2 
where t2.proposal_job_ref = t1.proposal_job_ref 
and t2.work_date <= t1.work_date 
and t2.work_date >= '01/04/2013' ) 
as [Days Spent Since 1st April 2013],

--GET TOTAL DAYS REMAINING ON THE PROPOSAL 
(select sum(pta2.days_assigned) 
from proposal_time_assigned pta2
where pta2.proposal_ref_code = t1.proposal_job_ref )
- 
(select sum(t2.timesheet_time / 8.0) 
from timesheet_entries t2 
where t2.proposal_job_ref = t1.proposal_job_ref 
and t2.work_date <= t1.work_date
 ) as [Total Days Remaining]

from timesheet_entries t1, 
consultant c1, 
proposal p1, 
proposal_time_assigned pta1

where (pta1.consultant_id = c1.consultant_id)
     and (t1.proposal_job_ref = p1.proposal_ref_code) 
     and (pta1.proposal_ref_code = t1.proposal_job_ref)
     and (t1.code_id = @org_id) and (t1.work_date >= @start_date) and (t1.work_date <= @end_date) 
    and (t1.proposal_job_ref <> '0')

order by 2, 3

检查上述查询是否有任何索引选项&amp;每个表格要处理的记录数。

答案 1 :(得分:1)

检查数据库中是否有下表中的索引(如果这些列未编入索引,则从索引每个列开始)。

  • proposal_time_assigned.proposal_ref_code
  • proposal_time_assigned.consultant_id
  • timesheet_entries.code_id
  • timesheet_entries.proposal_job_ref
  • timesheet_entries.work_date
  • consultant.consultant_id
  • proposal.proposal_ref_code

如果没有所有这些索引,则不会改进此查询。

您的查询中唯一会影响性能的是您过滤[work_date]的方式。您当前的语法会导致表扫描:

--bad
and t2.work_date <= t1.work_date 
and t2.work_date >= '01/04/2013'

此语法使用索引(如果存在)并且速度会快得多:

--better
and t2.work_date between t1.work_date and '01/04/2013'

答案 2 :(得分:1)

根据给出的信息,我必须对某些表关系进行有根据的猜测。如果您发布表结构,索引等...我们可以完成此查询的剩余列。

截至目前,此查询计算“已分配天数”,“已花费的天数”和“剩余天数” 对于KEY“timesheet_id和proposal_job_ref”

我们必须看到的是“work_date”,“timesheet_time”,“[Person]”,“proposal_title”如何与之相关联。 这些是按人和Proposal_title计算的吗?

您可以使用sqlfiddle向我们提供示例数据和输出,这样我们就可以解决完整数据的含义,而不是进行猜测。

    SELECT 
             q1.timesheet_id
            ,q1.proposal_job_ref
            ,q1.[Total Days Assigned]
            ,q2.[Days Spent Since 1st April 2013]
            ,(
                q1.[Total Days Assigned] 
                - 
                q2.[Days Spent Since 1st April 2013]
            ) AS [Total Days Remaining]
    FROM
    (
        select 
            t1.timesheet_id
            ,t1.proposal_job_ref
            ,sum(t4.days_assigned) as [Total Days Assigned]
        from tbl1.timesheet_entries t1
        JOIN tbl1.proposal t2
            ON t1.proposal_job_ref=t2.proposal_ref_code
        JOIN tbl1.proposal_time_assigned t4
            ON t4.proposal_ref_code = t1.proposal_job_ref
        JOIN tbl1.consultant t3
            ON t3.consultant_id=t4.consultant_id
        WHERE t1.code_id = @org_id
            AND t1.work_date BETWEEN @start_date AND @end_date
            AND t1.proposal_job_ref <> '0'
        GROUP BY t1.timesheet_id,t1.proposal_job_ref
    )q1
    JOIN
    (
        select 
            tbl1.timesheet_id,tbl1.proposal_job_ref
            ,isnull(sum(tbl1.timesheet_time / 8.0), '0') AS [Days Spent Since 1st April 2013]
        from tbl1.timesheet_entries tbl1
        JOIN tbl1.timesheet_entries tbl2
            ON tbl1.proposal_job_ref=tbl2.proposal_job_ref
            AND tbl2.work_date <= tbl1.work_date
            AND tbl2.work_date >= '01/04/2013'
        WHERE tbl1.code_id = @org_id
            AND tbl1.work_date BETWEEN @start_date AND @end_date
            AND tbl1.proposal_job_ref <> '0'
        GROUP BY tbl1.timesheet_id,tbl1.proposal_job_ref
    )q2
        ON q1.timesheet_id=q2.timesheet_id 
        AND q1.proposal_job_ref=q2.proposal_job_ref