为什么COUNT(DISTINCT fieldA)比COUNT(DISTINCT LTRIM(RTRIM(UPPER(fieldA))))慢?

5

我对 SQL Server 2005 中的执行计划很陌生,但这让我感到困惑。

当我运行以下代码时……

((SELECT COUNT(DISTINCT StudentID)
 FROM vwStudentUnitSchedules AS v
 WHERE v.UnitActive = 1
   AND v.UnitOutcomeCode IS NULL
   AND v.UnitCode = su.UnitCode
   AND v.StartDate = su.StartDate
   AND v.StudentCampus = st.StudentCampus) - 1) AS ClassSize

获取类大小时,如果以通用方式运行,需要大约30秒的时间才能超时。

但是,当我进行轻微修改后运行它...

 ((SELECT COUNT(DISTINCT LTRIM(RTRIM(UPPER(StudentID))))
     FROM vwStudentUnitSchedules AS v
     WHERE v.UnitActive = 1
       AND v.UnitOutcomeCode IS NULL
       AND v.UnitCode = su.UnitCode
       AND v.StartDate = su.StartDate
       AND v.StudentCampus = st.StudentCampus) - 1) AS ClassSize

它几乎瞬间运行。

这是因为 LTRIM()、RTRIM() 和 UPPER() 函数吗?为什么它们会让事情变得更快呢?我想这是因为 COUNT(DISTINCT 是一个按从左到右字符计数的聚合函数?是的,StudentID 是一个 VARCHAR(10)。

谢谢。


1
听起来你是按顺序执行查询的,第二个查询被缓存了。在执行之前,你有清除缓存页面吗?第一个查询需要花费多长时间?你尝试过使用 set statistics io on 吗?查询计划看起来还好吗? - sisve
1
你好。如果你的学生ID是索引的一部分,对该列应用任何函数都会影响性能。这是因为查询优化器不再知道要使用哪个索引。如果你查看执行计划,你应该会注意到差异。 - Gatej Alexandru
1
你的结果一样吗? - Amir Keshavarz
1
你可以将 .sqlplan 上传到某个文件共享网站或 pastebin,或者将图形计划作为图像上传(这更方便,尽管不太详细)。但是我以为问题已经解决了,对吗? - usr
@usr:是的,就像下面所说的。无论如何,谢谢。 - LoftyWofty
显示剩余8条评论
1个回答

2

查询计划缓存肯定会影响第二次运行的速度。

如果这不是问题的话,可能是因为修剪(trim)操作。选择不同的选项是为了匹配每个字符串,如果这些字符串被修剪,则字符数量较少。

根据您的数据库引擎,还可以查看二进制校验和是否能够加快速度。如果有效,那么我的理论就是正确的。

 ((SELECT COUNT(DISTINCT BINARY_CHECKSUM(LTRIM(RTRIM(UPPER(StudentID)))))

是的,这也非常快。我将其更改为SELECT COUNT(DISTINCT BINARY_CHECKSUM(StudentID))。如果我不删除任何多余的空格(如空格),数据库似乎正在进行逐个字符的比较。 - LoftyWofty

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接