视图中Where子句之前的Select语句处理
-
12-11-2019 - |
题
我有一个选择 charindex 的子字符串的语句,如下所示:
SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE
CHARINDEX('ABC', StringField) > 5
当我在选择查询中运行上述语句时,结果返回得很好。当我在架构绑定索引视图中运行上述语句时,出现以下错误:
Invalid length parameter passed to the LEFT or SUBSTRING function
为了解决这个问题,我将编写一个函数来获取 CharIndex 的最大值和 0,以消除负值的可能性。但有谁知道为什么 where 子句不会过滤掉 select 语句?
解决方案
因为查询中幕后操作的顺序无法保证。
我猜如果您检查执行计划,您会看到它并行执行这两项检查 - 这是因为这两个操作都不能使用索引!
无论如何,SQL 都需要将该字段的每一行加载到内存中,因此它会同时针对这两个条件进行处理。
你可以试试 WITH (MAXDOP(1))
作为查询提示,看看这是否可以阻止问题出现,或者您可以执行子选择来强制执行顺序:
SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
FROM (
SELECT Stringfield
FROM Table
WHERE CHARINDEX('ABC', StringField) > 5
) as [X]
当我使用以下命令检查字段是否为数字时,我遇到了类似的问题 PATINDEX
我认为其中一栏将其转换为 int
- 我收到转换错误,因为引擎正在转换每一行,因为我的过滤器不可SARGable。
其他提示
这是一个丑陋的解决方法,但你也许可以这样做:
DECLARE @x TABLE(StringField VARCHAR(32));
INSERT @x SELECT 'ABC'
UNION ALL SELECT 'A'
UNION ALL SELECT 'AAAAAAAABC';
SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;
SELECT SUBSTRING(StringField,
CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 1 END,
CHARINDEX('ABC', StringField) -
CASE WHEN CHARINDEX('ABC', StringField) > 5 THEN 5 ELSE 0 END)
FROM @x
WHERE CHARINDEX('ABC', StringField) > 5;
两者产量:
---
AAA
但我怀疑您认为后者会被允许。它很丑陋,但不幸的是,除非您首先将过滤后的数据转储到#temp表中(或者尝试看看是否 MAXDOP
可靠地消除了问题)您将无法对处理顺序进行太多控制。
另一个想法是尝试在表中放入计算列(但我不确定如果您尝试创建索引视图这会有所帮助 - 可能仍然会出现复杂情况)。或者使用该表达式的筛选索引,而不是索引视图。如果我们知道索引视图要完成的任务以及您使用的 SQL Server 版本,可能会有多种“解决方案”。
不隶属于 StackOverflow