Quantcast
Channel: Erik Darling – Brent Ozar Unlimited®
Viewing all articles
Browse latest Browse all 370

Implicit vs. Explicit Conversion

$
0
0

Everyone knows Implicit Conversion is bad

It can ruin SARGability, defeat index usage, and burn up your CPU like it needs some Valtrex. But what about explicit conversion? Is there any overhead? Turns out, SQL is just as happy with explicit conversion as it is with passing in the correct datatype in the first place.

Here’s a short demo:

SET NOCOUNT ON;	

SELECT
    ISNULL([x].[ID], 0) AS [ID] ,
    ISNULL(CAST([x].[TextColumn] AS VARCHAR(10)), 'A') AS [TextColumn]
INTO
    [dbo].[Conversion]
FROM
    ( SELECT TOP 1000000
        ROW_NUMBER() OVER ( ORDER BY ( SELECT NULL ) ) ,
        REPLICATE('A', ABS(CONVERT(INT, CHECKSUM(NEWID()))) % 10 + 1)
      FROM
        [sys].[messages] AS [m] ) [x] ( [ID], [TextColumn] );

ALTER TABLE [dbo].[Conversion] ADD CONSTRAINT [pk_conversion_id] PRIMARY KEY CLUSTERED ([ID]);

CREATE NONCLUSTERED INDEX [ix_text] ON [dbo].[Conversion] ([TextColumn])

One table, one million rows, two columns! Just like real life! Let’s throw some queries at it. The first one will use the wrong datatype, the second one will cast the wrong datatype as the right datatype, and the third one is our control query. It uses the right datatype.

SET STATISTICS TIME, IO ON 

DECLARE @txt NVARCHAR(10) = N'A',
@id	INT

SELECT @id = [c1].[ID]
FROM [dbo].[Conversion] AS [c1]
WHERE [c1].[TextColumn] = @txt
GO 

DECLARE @txt NVARCHAR(10) = N'A',
@id	INT

SELECT @id = [c1].[ID]
FROM [dbo].[Conversion] AS [c1]
WHERE [c1].[TextColumn] = CAST(@txt AS VARCHAR(10) )
GO 

DECLARE @txt VARCHAR(10) = 'A',
@id	INT

SELECT @id = [c1].[ID]
FROM [dbo].[Conversion] AS [c1]
WHERE [c1].[TextColumn] = @txt 
GO

The results shouldn’t surprise most of you. From statistics time and I/O, the first query is El Stinko. The second two were within 1ms of each other, and the reads were always the same over every execution. Very little CPU, far fewer reads.

Query 1:
Table 'Conversion'. Scan count 1, logical reads 738, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 47 ms,  elapsed time = 47 ms.

Query 2:
Table 'Conversion'. Scan count 1, logical reads 63, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 4 ms.

Query 3:
Table 'Conversion'. Scan count 1, logical reads 63, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
CPU time = 0 ms, elapsed time = 5 ms.

So there you go

Explicit conversion of parameter datatypes doesn’t carry any horrible overhead. Is it easier to just pass in the correct the datatype? Yeah, probably, but you might be in a position where you can’t control the parameter datatype that’s incoming, but you can CAST or CONVERT it where it touches data.

Thanks for reading!

Brent says: the key here is that we’re taking an incoming NVARCHAR variable, and casting it in our query to be VARCHAR to match the table definition. This only works if you can guarantee that the app isn’t going to pass in unicode – but in most situations, that’s true, because the same app is also responsible for inserting/updating data in this same table, so it’s already used to working with VARCHAR data. Also, just to be clear, Erik’s talking about casting the variable – NOT every row in the table. That part still blows.


Viewing all articles
Browse latest Browse all 370

Trending Articles