我有一个在WHERE中没有is null
的情况下在4秒内运行的查询,但使用is null
需要差不多一分钟。我已经了解了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的空检查?
使用此SQL 创建 view_scores
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
是最终执行空检查的字段。我可以以任何我想要的方式修改视图,并以我想要的任何方式编制索引,但这就是它。
带有空检查的执行计划包括一组非常疯狂的排序和与分数和coding_exercise_score_detail相关的哈希匹配。
答案 0 :(得分:0)
您可以在视图上放置索引
Create Indexed Views
在view_scores.archived_date上尝试索引
答案 1 :(得分:0)
通常,JOIN ON
条件和WHERE
或ORDER BY
中涉及的所有列都应编入索引以获得更好的性能。由于您说view_scores
是一个视图,因此请检查实际表中的列archived_date
是否已编入索引。如果没有,那么您应该考虑在该列上创建索引。
您也可以考虑将该条件添加到视图创建逻辑本身。
view_scores.archived_date is null
答案 2 :(得分: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)