Выберите обработку оператора перед предложением Where в поле зрения

StackOverflow https://stackoverflow.com/questions/9434699

  •  12-11-2019
  •  | 
  •  

Вопрос

У меня есть оператор, который выбирает подстроку хариндекса следующим образом:

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 не отфильтровывает оператор выбора?

Это было полезно?

Решение

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

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

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 - у меня есть ошибки преобразования, потому что двигатель преобразует каждую строку с момента моегоФильтры не были саргабельными.

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top