在视图中的Where子句之前选择语句处理

时间:2012-02-24 16:49:45

标签: sql database database-indexes

我有一个语句选择charindex的子字符串,如下所示:

SELECT SUBSTRING(StringField, 5, CHARINDEX('ABC', StringField) - 5)...
WHERE 
CHARINDEX('ABC', StringField) > 5

当我在select查询中运行上述语句时,结果返回正常。当我在模式绑定索引视图中运行上述语句时,我收到此错误:

Invalid length parameter passed to the LEFT or SUBSTRING function

为了解决这个问题,我将编写一个函数来获取CharIndex的Max和0以消除负值的可能性。但有谁知道为什么where子句不会过滤掉select语句?

2 个答案:

答案 0 :(得分:2)

因为无法保证查询中幕后操作的顺序。

我猜你是否检查了执行计划,你会看到它并行执行两项检查 - 这是因为这两种操作都不能使用索引!

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,因此引擎正在转换每一行。

答案 1 :(得分:1)

这是一个丑陋的解决方法,但你可以这样做:

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版本,可能会有几个“解决方案”。