繁体   English   中英

我可以修改索引或视图以提高'is null'子句的性能

[英]Can I modify indexes or views to improve 'is null' clause performance

我有一个查询,它在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是最终对其执行空检查的字段。 我可以按照自己想要的任何方式修改视图,并以自己想要的任何方式编制索引,仅此而已。

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

执行计划详细信息

您可以在视图上放置索引。
创建索引视图
尝试对view_scores.archived_date进行索引

通常,应为JOIN ON条件以及WHEREORDER BY涉及的所有列建立索引,以提高性能。 由于您说view_scores是一个视图,因此请检查实际表中的archived_date列是否archived_date建立索引。 如果不是,则应考虑在该列上创建索引。

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

view_scores.archived_date is null
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
        )

我会看这个
加入中的OR通常很慢
不会使用的选择和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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM