【问题标题】:Slow SQL Server Query due to calculations?由于计算导致 SQL Server 查询缓慢?
【发布时间】:2013-11-20 18:44:53
【问题描述】:

我负责使用 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 查询中执行上述计算?还是应该在代码中完成?

任何帮助将不胜感激。

谢谢。

【问题讨论】:

  • Bad habits to kick : using old-style JOINs - 旧式 逗号分隔的表格列表 样式已随 ANSI-92 SQL 标准(超过 20 年前)
  • 这是转换为 SQL Server 表值函数而不是单个查询的好候选...
  • 使用逗号分隔的表和 where 子句代替连接不会对性能产生任何影响。
  • @marc_s - 是的,但这只是样式,查询优化器不应该受到太大的负面影响,尽管在某些情况下可能会。
  • @DavidFleeman:当然,它可能不会对性能有太大帮助,但它肯定将有助于可读性和最新的现行标准!

标签: asp.net sql sql-server timeout


【解决方案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】:

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

    截至目前,此查询计算“已分配天数”、“已用天数”和“剩余天数” 对于 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
    

    【讨论】:

    • 谢谢,帮了大忙。
    【解决方案3】:

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

    1> 没有为表格提供别名。 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
    

    检查上述查询是否有任何索引选项和要从每个表中处理的记录数。

    【讨论】:

      猜你喜欢
      • 2017-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-01
      • 2019-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多