• Link to Facebook
  • Link to Instagram
  • Link to LinkedIn
  • Link to Youtube
  • Link to X
Call Us Today! 512-640-5750
Data Architect as a Service | Remote DBA Services
  • Services
    • Analytics Architecture
    • Database Architecture
    • Software Architecture
    • Microsoft Fabric Consulting
      • Microsoft Fabric Health Check
  • About Us
    • Testimonials
    • Recommendation Program
    • Jobs
      • Data Engineering Consultant
      • Principal Data Analytics Architect
  • Resources
    • Blog
    • Videos
  • Contact
  • Click to open the search input field Click to open the search input field Search
  • Menu Menu
John Sterrett

SQL Server Implicit Conversions Matter!

Performance Tuning

While not all implicit conversions are equal implicit conversions matter. For example, just this week I ran into a trivial code change that caused some severe regression in performance. One simple filter change caused a query to consume 227 million reads compared to 212 reads. What did the filter do? Well, it forced an implicit conversion.

In this blog post you will learn what is an implicit conversion, how to identify it, and also how do you find the implicit conversion leading to the highest amount of reads in the query store.

What is a SQL Server Implicit Conversion?

This is a great question. The answer is when SQL Server optimizer has to convert data in a column to match the type you are using in your query. For example, if you had a column that was an Integer and you decided to filter off of a string “varchar” variable. ORM’s like Entity Framework is notoriously known for this. You would end up forcing an implicit conversion. This will force the optimizer to read every value in the column and cast it so the column can then be filtered based off your variable or another column that doesn’t match the same data type.

Let’s look at an example. Yes, this is exactly similar to the example mentioned in the first paragraph that consumed 227 million reads. We are just going to simplify it down for you with a copy of the AdventureWorks modified database.

SalesOrderID column is an INT, not VARCHAR. We are going to filter with a VARCHAR data type using the LIKE operator as shown below.

SELECT [SalesOrderID]
      ,[SalesOrderDetailID]
      ,[CarrierTrackingNumber]
      ,[OrderQty]
      ,[ProductID]
      ,[SpecialOfferID]
      ,[UnitPrice]
      ,[UnitPriceDiscount]
      ,[LineTotal]
      ,[rowguid]
      ,[ModifiedDate]
  FROM [AdventureWorks2012].[Sales].[SalesOrderDetailEnlarged]
  WHERE SalesOrderID LIKE '43659'

This will produce the following execution plan and statistics which is not ideal at all. We will get a warning for the implicit conversion and also go parallel scanning the whole table due to this conversion.

Implicit Conversion Forces Table Scan
A SQL Server Implicit Conversion Forces a Table Scan
Implicit Conversions hurt performance
SQL Server Implicit Conversions causing the whole table to be read.
statistics for our implicit conversion
The following is statistics for our implicit conversion

How to fix Implicit Conversions in SQL Server

Now that we know how to identify an implicit conversion I bet you might be wondering how do you resolve them? They usually come in two flavors. First, the columns do not match data types on a join. Second, the parameter or literals data type does not match with the column. Today, we will focus on the second time in the code below.

The only thing we change in our code is the type of filter.

SELECT [SalesOrderID]
      ,[SalesOrderDetailID]
      ,[CarrierTrackingNumber]
      ,[OrderQty]
      ,[ProductID]
      ,[SpecialOfferID]
      ,[UnitPrice]
      ,[UnitPriceDiscount]
      ,[LineTotal]
      ,[rowguid]
      ,[ModifiedDate]
  FROM [AdventureWorks2012].[Sales].[SalesOrderDetailEnlarged]
  WHERE SalesOrderID = 43659
Parameter matches column data type
The literal parameter matches with the column data type.
Gone from 76k reads to 3!

How do I get Implicit Conversions from the Query Store?

Now that you understand implicit conversions you might wonder how do I find them? Well, hopefully, you are on SQL Server 2016 or higher and can query the execution plans in query store. If not, check out Jonathan Kehayias example to find implicit conversions in the plan cache.

Disclaimer: Plan cache will only have execution plans that are still in memory. Query store will only have execution plans that are in the query store. Also, I added variables for the start date, end date, and top offenders. Performance milage will vary based on how your query store is configured and used. run the query below at your own risk!

DROP TABLE IF EXISTS #plans
DROP TABLE IF EXISTS #tmp1
DROP TABLE IF EXISTS #tmp2
DROP TABLE IF EXISTS #finalplan
GO

DECLARE @StartDate datetime = dateadd(d,-1, getdate()),
 @EndDate datetime = getdate(), 
 @TopStmts INT = 1000

SELECT TOP (@TopStmts)
	SUM(qrs.count_executions) * AVG(qrs.avg_logical_io_reads) as est_logical_reads,
    SUM(qrs.count_executions) AS sum_executions,
    AVG(qrs.avg_logical_io_reads) AS avg_logical_io_reads,
    SUM(qsq.count_compiles) AS sum_compiles,
   qsp.plan_id
INTO #tmp1
FROM sys.query_store_query qsq
JOIN sys.query_store_plan qsp on qsq.query_id=qsp.query_id
JOIN sys.query_store_runtime_stats qrs on qsp.plan_id = qrs.plan_id
WHERE qrs.first_execution_time >= @StartDate 
AND qrs.last_execution_time <= @EndDate
group by qsp.plan_id
ORDER BY est_logical_reads DESC 


SELECT cte.*, TRY_CAST (qsp.query_plan AS XML) AS xml_query_plan 
INTO #tmp2
FROM #tmp1 cte
JOIN sys.query_store_plan qsp ON cte.plan_id = qsp.plan_id


SELECT #tmp2.* 
INTO #plans
FROM #tmp2;

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DECLARE @dbname SYSNAME 
SET @dbname = QUOTENAME(DB_NAME());

;WITH XMLNAMESPACES 
   (DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan') 
SELECT p.est_logical_reads, p.sum_executions, p.avg_logical_io_reads, p.plan_id
,   stmt.value('(@StatementText)[1]', 'varchar(max)') AS SQLStmt, 
   t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)') AS SchemaName, 
   t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)') AS TableName, 
   t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)') AS ColumnName, 
 ic.DATA_TYPE AS ConvertFrom, 
 ic.CHARACTER_MAXIMUM_LENGTH AS ConvertFromLength, 
   t.value('(@DataType)[1]', 'varchar(128)') AS ConvertTo, 
   t.value('(@Length)[1]', 'int') AS ConvertToLength,
   p.xml_query_plan
   INTO #finalplan
   FROM #plans p
CROSS APPLY xml_query_plan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple') AS batch(stmt) 
CROSS APPLY stmt.nodes('.//Convert[@Implicit="1"]') AS n(t) 
CROSS APPLY stmt.nodes('.//PlanAffectingConvert[@ConvertIssue="Cardinality Estimate"]') AS ce(pt) 
JOIN INFORMATION_SCHEMA.COLUMNS AS ic 
ON QUOTENAME(ic.TABLE_SCHEMA) = t.value('(ScalarOperator/Identifier/ColumnReference/@Schema)[1]', 'varchar(128)') 
   AND QUOTENAME(ic.TABLE_NAME) = t.value('(ScalarOperator/Identifier/ColumnReference/@Table)[1]', 'varchar(128)') 
   AND ic.COLUMN_NAME = t.value('(ScalarOperator/Identifier/ColumnReference/@Column)[1]', 'varchar(128)') 
WHERE t.exist('ScalarOperator/Identifier/ColumnReference[@Database=sql:variable("@dbname")][@Schema!="[sys]"]') = 1


SELECT fp.est_logical_reads, fp.sum_executions, fp.avg_logical_io_reads, fp.plan_id, 
qsq.query_id, qsq.query_hash, fp.SQLStmt, fp.SchemaName, fp.TableName, 
fp.ColumnName, fp.ConvertFrom, fp.ConvertTo, fp.ConvertFromLength, fp.ConvertToLength, fp.xml_query_plan
FROM #finalplan fp
JOIN sys.query_store_plan qsp ON fp.plan_id = qsp.plan_id
JOIN sys.query_store_query qsq ON qsp.query_id = qsq.query_id
ORDER BY fp.est_logical_reads DESC	

April 29, 2019/by John Sterrett
Tags: implicit conversion, query store
Share this entry
  • Share on Facebook
  • Share on X
  • Share on X
  • Share on LinkedIn
  • Share on Reddit
  • Share by Mail
https://procuresql.com/wp-content/uploads/2018/09/Procure-SQL-September-2018-Training-Opportunities-1-1.jpg 540 1018 John Sterrett /wp-content/uploads/2024/05/Data-Architecture-as-a-Service-with-ProcureSQL.png John Sterrett2019-04-29 22:57:252019-04-29 22:57:25SQL Server Implicit Conversions Matter!
You might also like
Procure SQL SQL Saturday Chicago SQL Saturday Chicago
Procure SQL Automatic Tuning Automatic Tuning in the Real-World
Why is my SQL Server query slower than normal?
What is SQL Server parameter sniffing and data skew?
Query Store 101
Join Our Newsletter
  Thank you for Signing Up
Please correct the marked field(s) below.
1,true,6,Contact Email,21,false,1,First Name,21,false,1,Last Name,2
Search Search

Blog Categories

  • $150 Challenge
  • Advice
  • Announcements
  • Artificial Intelligence
  • Awards
  • Azure Data Factory
  • C-Level
  • Cloud
  • Community
  • Conferences
  • Data Architecture
  • Data Integration
  • Data Intergration
  • Data Visualization
  • Data Warehousing
  • DBA 101
  • Design
  • Disaster Recovery or High Availability
  • Education
  • Fabric Dev Ops
  • Fabric Lakehouse
  • Fabric Lakehouses
  • Fabric Mirroring
  • Fabric Notebooks
  • Features
  • General
  • Health Checks
  • Lab
  • Microsoft Fabric
  • Microsoft Technologies
  • Newsletter
  • Performance Tuning
  • Power BI
  • ProcureSQL
  • Python
  • Reporting
  • Security
  • SQL Server
  • SQL Server
  • sql server 101
  • SQLServerPedia Syndication
  • syndication
  • The Blog
  • Uncategorized
  • Visual Studio Credit

Tags

#SQLFamily automatic tuning availability group azure backup Backups career Data Governance Data Loss Data Platform DBA Denver Differential Backup Disaster Recovery Fabric Fabric Architecture Full Backup High Availability Houston Marketing Database Administrator Microsoft Microsoft Fabric Microsoft SQL Server mirroring parameter sniffing PASS performance tuning Professional Development query store Recovery Recovery Model Restores Security SQL Saturday SQL Server SQL Server 2017 sql server 2019 SQL Server 2022 sql server 2025 SSMS System Databases Transaction Log Backup tsqltuesday Tuning Wait Stats

Archives

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • May 2026
  • April 2026
  • March 2026
  • February 2026
  • November 2025
  • October 2025
  • September 2025
  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • January 2025
  • December 2024
  • November 2024
  • October 2024
  • September 2024
  • August 2024
  • July 2024
  • June 2024
  • May 2024
  • February 2024
  • January 2024
  • November 2023
  • October 2023
  • March 2023
  • January 2023
  • May 2022
  • April 2022
  • November 2021
  • September 2020
  • August 2020
  • April 2020
  • March 2020
  • February 2020
  • January 2020
  • December 2019
  • November 2019
  • September 2019
  • July 2019
  • April 2019
  • November 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • April 2018
  • March 2018
  • February 2018
  • January 2018
  • November 2017
  • October 2017
  • August 2017
  • July 2017
  • June 2017
  • April 2017
  • December 2016
  • November 2016
  • October 2016
  • July 2016
© Copyright 2026 - ProcureSQL - 1464 East Whitestone Blvd., Suite 1902 Cedar Park, TX 78613, USA
  • Link to Facebook
  • Link to Instagram
  • Link to LinkedIn
  • Link to Youtube
  • Link to X
Link to: Automatic Tuning: Execution Plan Correction Link to: Automatic Tuning: Execution Plan Correction Automatic Tuning: Execution Plan CorrectionAutomatic Tuning: Execution Plan Correction Link to: It’s official Link to: It’s official Procure Microsoft Gold PartnerIt’s official
Scroll to top Scroll to top Scroll to top
Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
View preferences
  • {title}
  • {title}
  • {title}