Skip to content

TRY_CAST и TRY_PARSE могут возвращать разные результаты

Пересказ статьи Joe Obbish. TRY_CAST and TRY_PARSE Can Return Different Results


Имеется множество руководств, утверждающих, что TRY_CAST является более быстрой и более современной версией TRY_PARSE, и что TRY_PARSE следует использовать только тогда, когда вам необходимо установить необязательный языковой параметр (culture). Однако эти две функции могут возвращать в некоторых случаях различные результаты даже без параметра culture.


Парсинг


Сначала я заброшу миллион строк в единственный столбец столбец типа varchar временной таблицы:

CREATE TABLE #number_as_string (why_tho VARCHAR(100));
INSERT INTO #number_as_string (why_tho)
SELECT ISNULL(CAST(TRY_CAST(q.RN % 33000 AS SMALLINT) AS VARCHAR(100)), '')
FROM
(
SELECT TOP (1000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) q;

Предположим, что я хочу подсчитать число строк, которые являются числами, подпадающие под ограничения типа данных TINYINT. Следующий код занимает 36937 мс времени процессора на моей машине и возвращает значение 7935:

SELECT COUNT_BIG(*)
FROM #number_as_string
WHERE TRY_PARSE(why_tho AS TINYINT) IS NOT NULL
OPTION (MAXDOP 1);

Плохая производительность запроса не является неожиданной. Документация говорит следующее о TRY_PARSE:

Помните, что имеется определенное падение производительности при парсинге строковых значений.

Кастинг


Я могу использовать TRY_CAST для того, чтобы избежать накладных расходов, связанных с парсингом строк при использовании TRY_PARSE. Следующий код потребляет 110 мс времени процессора, поэтому он значительно быстрей, чем предыдущий запрос:

SELECT COUNT_BIG(*)
FROM #number_as_string
WHERE TRY_CAST(why_tho AS TINYINT) IS NOT NULL
OPTION (MAXDOP 1);

Однако этот запрос возвращает значение 14895, почти удваивая предыдущее число. Результаты запроса отличаются, потому что TRY_PARSE возвращает NULL для пустых строк, в то время как TRY_CAST возвращает 0. Преобразованный запрос (особая благодарность Stephen Morris) возвращает ожидаемое значение 7935 и потребляет 175 мс времени процессора:

SELECT COUNT_BIG(*)
FROM #number_as_string
WHERE TRY_CAST(why_tho AS TINYINT) IS NOT NULL AND why_tho NOT IN ('', '+', '-')
OPTION (MAXDOP 1);

Последние мысли


Дело не в том, что TRY_CAST возвращает неправильные результаты. В SQL Server пустая строка преобразуется в 0, когда проверяется целочисленный тип данных. Более того, когда TRY_CAST применяется к строке, тот, кто пишет запрос, обычно хочет получить только те значения, которые человек воспринял бы как число. TRY_PARSE, видимо, следует набору правил, который больше соответствует человеческому суждению о том, что является числом, а что нет. Во многих случаях все же хорошей идеей является избегать TRY_PARSE по причине падения производительности, однако не забудьте фильтровать пустые строки, если вы не хотите, чтобы они были включены в результирующий набор.
Категории: T-SQL

Обратные ссылки

Нет обратных ссылок

Комментарии

Показывать комментарии Как список | Древовидной структурой

Нет комментариев.

Автор не разрешил комментировать эту запись

Добавить комментарий

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Добавленные комментарии должны будут пройти модерацию прежде, чем будут показаны.