我有两个查询在SUBSTRING
语句中使用CASE
函数,如下所示:
CASE
WHEN Answer.ChoiceTitle = 'Neither Likely or Unlikely'
THEN 'Neither Likely nor Unlikely'
WHEN Answer.ChoiceTitle LIKE '[1-5]%'
THEN SUBSTRING(Answer.ChoiceTitle, 3, LEN(Answer.ChoiceTitle) - 2)
ELSE Answer.ChoiceTitle
END AS Recommendation
当单独运行时,两个查询都运行得很好但是当我尝试将两个结果集与UNION ALL
组合时,我收到错误消息:
传递给LEFT或SUBSTRING函数的长度参数无效
在尝试弄清楚为什么会出现此错误的同时,我将以下内容添加到每个语句中,UNION ALL
现在完全正常。
MIN(LEN(Answer.ChoiceTitle)) OVER() AS MinLength
为什么我会收到此错误?
执行计划
计划执行计划UNION ALL
- https://www.brentozar.com/pastetheplan/?id=rksFnuLS-
第一个陈述的实际执行计划 - https://www.brentozar.com/pastetheplan/?id=r1Z-pO8HW
第二项陈述的实际执行计划 - https://www.brentozar.com/pastetheplan/?id=rkCTh_IBb
答案 0 :(得分:1)
这很可能导致您的错误:LEN(Answer.ChoiceTitle) - 2
当评估值小于0时,它将引发错误。
请改为尝试:
CASE
WHEN Answer.ChoiceTitle = 'Neither Likely or Unlikely'
THEN 'Neither Likely nor Unlikely'
WHEN Answer.ChoiceTitle LIKE '[1-5]%' and LEN(Answer.ChoiceTitle) > 2
THEN SUBSTRING(Answer.ChoiceTitle, 3, LEN(Answer.ChoiceTitle) - 2)
ELSE Answer.ChoiceTitle
END AS Recommendation
由于你刚刚摆脱了前两个字符,你可以使用stuff()
代替:
CASE
WHEN Answer.ChoiceTitle = 'Neither Likely or Unlikely'
THEN 'Neither Likely nor Unlikely'
WHEN Answer.ChoiceTitle LIKE '[1-5]%'
THEN stuff(Answer.ChoiceTitle,1,2,'')
ELSE Answer.ChoiceTitle
END AS Recommendation
如果长度小于3,这将给你一个空字符串,否则它将删除Answer.ChoiceTitle
的前两个字符。
至于为什么合并后的union all
查询会在其他人单独运行时抛出错误:
我在执行计划中看到了这种差异:
Hash Match > (Question & Survey nested loop) & (Compute Scalar > Answer) {Bottom right of execution plan without error}
vs
Hash Match > (Bitmap > Parallelism > Question) & (Compute Scalar > Answer) {Bottom right of execution plan with error}
嵌套循环版本可能会过滤在散列匹配之前导致错误的行,从而避免错误。
使用option (maxdop 1)
来防止并行可能会避免错误(已确认)在当前正在抛出它的查询上
这只是在为答案表中的行计算标量函数时,在过滤掉要运行表达式的行之前或之后。
union all
版本的成本较高,并且它超出了并行性的成本阈值,这就是为什么在不并行的情况下单独运行时不会看到相同的错误(特别是并行)以同样的方式)单独运行时成本较低。
所以基本上并行计划比其他计划更快地运行substring(),然后过滤掉抛出错误的行。