2016-01-21 23 views
0

我有一个查询在4秒内运行,但在WHERE中没有is null,但在is null需要几分钟时间。我已经阅读了空检查对性能的影响,但在这种情况下,我无法修改正在运行的查询。我可以修改索引或视图以提高'空'子句的性能

select 
    view_scores.* 
from 
    view_scores 
    inner join licenses AS l on view_scores.studentId = l.account_id 
where view_scores.archived_date is null 
    and l.school_id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' 
    and l.is_current = 1 
    and l.expiration_date >= SYSDATETIME() 

view_scores是一个视图,它汇集其他表中的数据的其他视图,其中一个视图最终保存archived_date字段。该字段中的空值意味着它尚未归档。同样,数据结构不在我的控制范围之内。我现在可以改变的是所涉及的观点的内部和表格上的索引。我是否有希望在不更改查询或模式的情况下显着提高对archived_date的空检查?

view_scores与此SQL

SELECT 
    ueh.user_id AS studentId, 
    vu.first_name + ' ' + vu.last_name AS studentName, 
    ueh.archived_date as archived_date, 
    MIN([ueh].[date_taken]) AS [started_date], 
    MAX(ueh.date_taken) AS last_date, 
    SUM(CAST([ueh].[actual_time] AS FLOAT)/600000000) AS [total_time_minutes], 
    SUM([exercise_scores].[earned_score]) AS [earned_score], 
    SUM([exercise_scores].[possible_score]) AS [possible_score], 
    AVG([exercise_scores].[percent_score]) AS [percent_score], 
    COUNT(ueh.exercise_id) AS total_exercises 
FROM [user_exercise_history] AS [ueh] 
LEFT JOIN 
    (
     SELECT 
      coding_exercise_score.exercise_id AS exercise_id, 
      coding_exercise_score.assessment_id AS assessment_id, 
      coding_exercise_score.user_id AS user_id, 
      coding_exercise_score.archived_date AS archived_date, 
      score.earned AS earned_score, 
      score.possible AS possible_score, 
      CASE score.possible 
       WHEN 0 THEN 0 
       WHEN score.earned THEN 100 
       ELSE 9.5 * POWER(CAST(score.earned AS DECIMAL)/score.possible * 100, 0.511) 
      END AS percent_score 
     FROM coding_exercise_score 
     INNER JOIN 
      coding_exercise_score_detail AS score_detail 
      ON coding_exercise_score.id = score_detail.exercise_score_id 
     INNER JOIN 
      score 
      ON score.id = score_detail.score_id 
     WHERE score_detail.is_best_score = 'True' 

     UNION 

     SELECT 
      mc_score.exercise_id AS exercise_id, 
      mc_score.assessment_id AS assessment_id, 
      mc_score.user_id AS user_id, 
      mc_score.archived_date AS archived_date, 
      score.earned AS earned_score, 
      score.possible AS possible_score, 
      CASE score.possible 
       WHEN 0 THEN 0 
       WHEN score.earned THEN 100 
       ELSE 9.5 * POWER(CAST(score.earned AS DECIMAL)/score.possible * 100, 0.511) 
      END AS percent_score 
     FROM 
      multiple_choice_exercise_score AS mc_score 
     INNER JOIN score 
      ON score.id = mc_score.score_id 
    ) AS [exercise_scores] 
     ON 
      (
       (ueh.exercise_id = [exercise_scores].exercise_id 
        AND ueh.user_id = [exercise_scores].user_id 
        AND (
         (ueh.assessment_id IS NULL AND [exercise_scores].assessment_id IS NULL) 
         OR ueh.assessment_id = [exercise_scores].assessment_id 
         ) 
        AND (ueh.archived_date IS NULL) 
       ) 
      ) 
INNER JOIN entity_account AS vu ON ((ueh.user_id = vu.account_id)) 
INNER JOIN (
    select 
     g.group_id, 
     g.entity_name, 
     g.entity_description, 
     g.created_on_date, 
     g.modified_date, 
     g.created_by, 
     g.modified_by, 
     agj.account_id 
    from entity_group as g 
    inner join 
     account_group_join as agj 
    on agj.group_id = g.group_id 
    where g.entity_name <> 'Administrators' 
     and g.entity_name <> 'Group 1' 
     and g.entity_name <> 'Group 2' 
     and g.entity_name <> 'Group 3' 
     and g.entity_name <> 'Group 4' 
     and g.entity_name <> 'Group 5' 
) AS g ON ueh.user_id = g.account_id 
WHERE ueh.status = 'Completed' 
GROUP BY ueh.user_id, vu.first_name, vu.last_name, ueh.archived_date 

user_exercise_history.archived_date AS archived_date是外地的空支票最终被执行针对创建。我可以以任何我想要的方式修改视图并以任何我想要的方式编制索引,但这就是它。

带有空检查的执行计划包含一组非常疯狂的排序和散列匹配,它们与score和coding_exercise_score_detail有关。

Execution Plan Details

+0

'EXEC sp_updatestats;'到你的数据库更新统计。任何改变? – Mihai

+0

所以如果你可以改变视图的内部,我们可以看到创建视图的sql吗? – HLGEM

+1

你是否在视图中调用任何其他视图?如果是这样,这通常是一个坏主意。我们几乎失去了一个数百万美元的客户,因为一个不知情的人对围绕着视图的观点进行了整体设计。 – HLGEM

回答

0

你可以把一个视图索引。
Create Indexed Views
上view_scores.archived_date

+0

我的理解是,您只能使用确定性值对视图进行索引。如果我理解,某些列是SUM或AVG或COUNT,这是非确定性的。这使得这不可能,对吗? – sonicblis

+0

只有当您想使其成为索引/实体化视图时,才可以在视图上创建索引。可能OP不希望那样。 – Rahul

+0

可悲的是,很少有意见实际符合索引标准。 – HLGEM

0

尝试的指数一般都参与JOIN ON条件和WHEREORDER BY应该被索引获得更好的性能列。既然你说view_scores是一个视图,然后检查实际表中的列archived_date是否索引。如果没有,那么你应该考虑在该列上创建一个索引。

您也可以考虑将该条件添加到视图创建逻辑本身。

view_scores.archived_date is null 
+0

在该字段中添加非聚集索引不会产生任何影响。在该字段上添加聚集索引使性能变差。 – sonicblis

+0

它是一个日期时间列吗?你也可以在视图创建本身中加入coolumn。 – Rahul

+0

它是(明显)允许空值的日期时间。你怎么把它包含在视图本身中?现在视图将其作为列返回。选择... ueh.archived_date作为archived_date ...,ueh是返回实际字段archived_date的另一个视图。 – sonicblis

0
ON  ueh.exercise_id = [exercise_scores].exercise_id 
    AND ueh.user_id  = [exercise_scores].user_id 
    AND ueh.archived_date IS NULL 
    AND (( ueh.assessment_id IS NULL 
      AND [exercise_scores].assessment_id IS NULL 
     ) 
      OR ueh.assessment_id = [exercise_scores].assessment_id 
     ) 

我想看看这个
或加入通常是缓慢的
皮克和ID将无法使用

ON  ueh.exercise_id = [exercise_scores].exercise_id 
    AND ueh.user_id  = [exercise_scores].user_id 
    AND ueh.archived_date IS NULL 
    AND isnull(ueh.assessment_id, -1) = isnull([exercise_scores].assessment_id, -1) 
相关问题