Выберите обработку заявления перед предложением Где в представлении - PullRequest
3 голосов
/ 24 февраля 2012

У меня есть оператор, который выбирает подстроку 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?

Ответы [ 2 ]

2 голосов
/ 24 февраля 2012

Поскольку порядок операций за кулисами в запросе не гарантирован.

Я предполагаю, что если вы проверите план выполнения, вы увидите, что он выполняет обе проверки параллельно -это потому, что ни одна операция не может использовать индекс!

В любом случае 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 голос
/ 24 февраля 2012

Это уродливый обходной путь, но вы могли бы сделать что-то вроде этого, возможно:

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 вы используете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...