Sql-server – User defined data types causing implicit conversions

sql serversql-server-2008-r2type conversionuser-defined-type

user defined datatypes, i'm looking at some execution plans and seeing implicit conversions happening in the background when a var is declared of type user defined data type and pulling a value into that var from a column that uses that user defined data type, it's showing it as an implicit conversion. Is this how it functions normally?

Added

ok so under Programmability -> Types -> User-Defined Data Types: there is

dbo.BOOL(char(1), not null)

and

ImageAccessibleFLAG TYPE_NAME is BOOL

New test

I can make an implicit conversion happen by doing the following
reasonforcreatetype is char(1) in the database

declare @test char(1)
set @test = (select top 1 reasonforcreatetype from result)
select @test

<ScalarOperator ScalarString="CONVERT_IMPLICIT(char(1),[Result].[ReasonForCreateType],0)">

Now I create a new table with a char(1) and a bool.
Run the same query and I don't get the implicit conversion.

Update 2

Ok when adding a new column under the same table having the issue I get the following

Warning: Columns have different ANSI_PADDING settings.
New columns will be created with ANSI_PADDING 'on'.

I'm assuming this has something to do with it now but I'm not sure the proper way to fix or correct these issues.

Best Answer

Okay, here is a repro:

USE tempdb;
GO
-- create one table with padding off:
SET ANSI_PADDING OFF;
GO
CREATE TABLE dbo.ap_off(a CHAR(1),
 CONSTRAINT ck_apOff CHECK (a IN ('N','Y')));
GO
-- and other with padding on:
SET ANSI_PADDING ON;
GO
CREATE TABLE dbo.ap_on(a CHAR(1),
 CONSTRAINT ck_apOn CHECK (a IN ('N','Y')));
GO

-- now, let's test queries 
-- with padding on or off
SET ANSI_PADDING OFF;
GO
-- implicit conversion:
DECLARE @off CHAR(1) = (SELECT a FROM dbo.ap_off);
-- implicit conversion:
DECLARE @on  CHAR(1) = (SELECT a FROM dbo.ap_on);

SET ANSI_PADDING ON;
GO
-- implicit conversion:
DECLARE @off CHAR(1) = (SELECT a FROM dbo.ap_off);
-- NO implicit conversion:
DECLARE @on  CHAR(1) = (SELECT a FROM dbo.ap_on);
GO

DROP TABLE dbo.ap_off, dbo.ap_on;

Here's the same version of the plan for the first three queries:

enter image description here

And the fourth, missing the compute scalar and any implicit conversion:

enter image description here

So, as I suggested above, this doesn't have anything to do with alias types, but rather the fact that ANSI_PADDING is problematic in a whole bunch of ways (here's a timely article, a Stack Overflow question, and Microsoft's own documentation from SQL Server 2005 telling you to stop using it).

My suggested approach is to build new versions of any table with these non-ANSI_PADDING columns (this time with ANSI_PADDING ON of course), migrate the data, drop the old tables, and rename the new tables. Or do the same type of thing with just the individual columns (in either case it's going to be a complicated and disruptive thing that you'll likely want to do during a maintenance window).

You can identify the affected tables with:

SELECT s.name, t.name
FROM sys.schemas AS s
INNER JOIN sys.tables AS t
ON s.[schema_id] = t.[schema_id]
WHERE t.is_ms_shipped = 0
AND EXISTS (SELECT 1 FROM sys.columns
 WHERE [object_id] = t.[object_id]
 AND is_ansi_padded = 0);

I would do this with one table or columns first, to see if it's worth it. See, in addition to eliminating the implicit conversions (which you think might cause performance issues), you should also demonstrate that performance will actually be different without them - and different enough to justify the effort, risk, and potential downtime. Otherwise, is it worth doing? We can't answer that, only you and your stakeholders can.