Question

The following is typical code generated by the SQL Server Management Studio to check for an object before deleting it:

if exists (select * from sys.objects where object_id = OBJECT_ID(N'get_summary')
and type in (N'P', N'PC'))
drop procedure get_summary;

Using the N prefix ensures that the literal string is a unicode constant (to match the data type for the object_id field in sys.objects).

The documentation for OBJECT_ID states that if the object_name is varchar it is implicitly converted to nvarchar. Is it safe to leave out the N here or are there situations where this can cause problems?

Was it helpful?

Solution

In the case of the OBJECT_ID() function, you are making a function call. Sql Server must resolve the argument type to the parameter type before calling the function, and so as long as the conversion doesn't lose information, you'll be fine either way. The work to convert that one string is infinitesimal.

However, in most situations you really do want your literal to match the target data type. Here's an example of why it can matter:

Imagine you have a table Foo with an varchar column Bar and a whole lot of rows. You write a query like this:

SELECT * FROM Foo WHERE Bar = N'baz'

There is a type mismatch between the literal (nvarchar) and column (varchar).

Pop quiz: what happens? You'd like Sql Server to convert the 'baz' literal to an varchar, because that is obviously more efficient.

Unfortunately, it won't work that way. Converting from nvarchar to varchar is a narrowing conversion. There are some things that can't be accurately expressed when converting from nvarchar to varchar, which means there is a potential to lose information in the conversion. Sql Server is not smart enough to know that your literal will map to the smaller data type without data loss*. If it converts your literal to a varchar, it might give you the wrong result, and Sql Server won't do that.

Instead, it has no choice but to convert your Bar column to an nvarchar. I'll say that again: it has no choice but to convert the value from every row in your Bar column to an nvarchar, even if you only get one row in the results. After all, it can't know if a given row matches your literal until it completes this conversion. Moreover, if you have an index on that column that would have helped, these converted values are not really the same value any more as what was stored in your index, meaning SQL Server can't use the index, either.

This could easily mean a night and day performance difference. A query that used to return instantly could literally take minutes to complete. A query that used to take a few seconds might now run for an hour.

The good news is that you're generally okay going the other direction... at least in this scenario. If Bar is an nvarchar column and you define baz as a varchar literal, that would be a widening conversion, and SQL Server will be more than happy to convert just the literal, and still use an index with the Bar column.

Of course, the best option is for the two values to have the same type.


* The actual conversion process follows simpler type precedence rules, but this "don't lose information or return bad data" reasoning is the principal those rules are designed to protect.

OTHER TIPS

OBJECT_ID is set up to deal with either varchar or nvarchar so this won't cause any problems http://technet.microsoft.com/en-us/library/ms190328.aspx

While there are no problems with OBJECT_ID. This isn't necessarily the case across the board. There are some situations where you do need to be carefull.

/*This works*/
EXEC sp_executesql N'PRINT ''nvarchar Hello World'''

/*This doesn't*/
EXEC sp_executesql 'PRINT ''varchar Hello World'''

Theoretically speacking Specifying nvarchar literals for things that genuinely are nvarchar like table names, whether you need to or not, is probably a good habit to get into and avoiding the extra overhead of the implicit type conversion will theoretically save you a tiny amount of CPU time but not that you're ever going to notice

It's not a habit I keep particularly well

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top