Что такое неявное преобразование?

Пересказ статьи Monica Rathbun. What is Implicit Conversion?

Это еще одна небольшая публикация по поводу простых изменений, которые вы можете сделать в своем коде, чтобы получить более оптимальный план выполнения. На этот раз речь пойдет о неявных преобразованиях. Неявное преобразование происходит, когда SQL Server должен автоматически преобразовать данные из одного типа в другой при сравнении значений, перемещении данных или комбинации одних значений с другими. Когда значения преобразуются в процессе обработки запроса, это добавляет излишнюю нагрузку, что влияет на производительность.

Вот замечательная схема от Microsoft, которая показывает допустимые преобразования типов, и какие из них требуют явного или неявного преобразования. В этой статье я не буду рассматривать явные преобразования, просто знайте, что они явно с помощью операторов CAST или COVERT указывают SQL Server, как преобразовать значение.

Давайте рассмотрим очень простой, но общий сценарий неявного преобразования. В нем таблица Employee содержит столбец NationalIDNumber, который определен на типе данных NVARCHAR. В запросе мы будем использовать предложение WHERE для поиска опреденного ID.

В нижеприведенном запросе мы запрашиваем NationalIDNumber, равный целому значению 14417807. Для сравнения этих двух типов данных SQL Server должен преобразовать NVARCHAR к INT. Это означает, что каждое значение в этом столбце должно пройти процесс преобразования, что вызывает сканирование таблицы (table scan).

USE AdventureWorks2016CTP3 
GO 
SET STATISTICS IO ON 
GO 
SELECT BusinessEntityID, NationalIDNumber, LoginID, HireDate,JobTitle
FROM HumanResources.Employee
WHERE NationalIDNumber = 14417807

В плане выполнения вы увидите восклицательный знак, предупреждающий, что в запросе имеется потенциальная проблема. Наведя курсор на оператор SELECT, можно увидеть, что происходит неявное преобразование (CONVERT_IMPLICIT), что может помешать оптимизатору использовать SEEK (поиск).


(1 row affected)

Table ‘Employee’. Scan count 1, logical reads 9, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Вопрос — как исправить это. Это действительно просто, но потребует изменения кода. Давайте вернемся к нашему запросу.

SELECT BusinessEntityID, NationalIDNumber, LoginID, HireDate,JobTitle
FROM HumanResources.Employee
WHERE NationalIDNumber = 14417807

Помните, что мы запрашивали целое значение. Простое добавление кавычек, ограничивающих значение, поможет нам решить проблему. Всегда важно знать, какого типа столбцы, которые вы используете в запросе. В данном примере, поскольку тип NVARCHAR, все, что необходимо сделать, это передать символьное значение. Это выполняется кавычками-ограничителями вокруг значения.

SELECT BusinessEntityID, NationalIDNumber, LoginID, HireDate,JobTitle
FROM HumanResources.Employee
WHERE NationalIDNumber = '14417807'

Просто посмотрим на результаты. Напомним, что выше мы имели число сканирований 1, логических чтений 9, физических чтений 0. Теперь при выполнении получим:

(1 row affected)

Table ‘Employee’. Scan count 0, logical reads 4, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

На графическом плане также видно, что предупреждение ушло, и мы имеем SEEK вместо SCAN, что значительно эффективней.


Имеется много способов, с помощью которых вы можете решить проблемы, связанные с неявными или явными преобразованиями и дополнительной нагрузкой, которую они создают. В большинстве случаев очень легко поправить ситуацию путем незначительных изменений в коде. Чтобы помочь вам найти их в вашей среде, Jonathan Kehayia написал запрос для нахождения столбцов с неявным преобразованием в кэше планов.

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