以下是SQL Server Management Studio在删除对象之前检查对象的典型代码:
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;
使用N前缀可确保文字字符串是unicode常量(以匹配sys.objects中object_id字段的数据类型)。
OBJECT_ID的文档指出,如果object_name是varchar,则会隐式转换为nvarchar。在这里省略N是否安全,或者是否存在可能导致问题的情况?
答案 0 :(得分:1)
对于OBJECT_ID()函数,您正在进行函数调用。 调用函数之前,Sql Server必须将参数类型解析为参数类型,因此只要转换没有丢失信息,您就可以了。转换那一个字符串的工作是无穷小的。
但是,在大多数情况下,您确实希望您的文字匹配目标数据类型。以下是一个重要原因的例子:
想象一下,您有一个表Foo
,其中包含varchar列Bar
和很多行。你写这样的查询:
SELECT * FROM Foo WHERE Bar = N'baz'
文字(nvarchar)和列(varchar)之间存在类型不匹配。
流行测验:会发生什么?您希望Sql Server将'baz'
文字转换为varchar,因为这显然更有效。
不幸的是,它不会那样工作。从nvarchar转换为varchar是缩小转换。从nvarchar转换为varchar时,有些内容无法准确表达,这意味着转换中有可能丢失信息。 Sql Server不够聪明,不知道您的文字将映射到较小的数据类型而不会丢失数据。如果它将您的文字转换为varchar,它可能会给您错误的结果,而Sql Server不会这样做。
相反,它别无选择,只能将Bar列转换为nvarchar。我再说一遍:它除了将Bar列中每一行的值转换为nvarchar之外别无选择,即使您只在结果中获得一行。在完成转换之前,它无法知道给定的行是否与您的文字匹配。此外,如果您在该列上有索引可能有帮助,那么这些转换后的值实际上不再是相同的值,而是存储在索引中的值,这意味着Sql Server无法使用索引了,或者。
这可能很容易意味着日夜的性能差异。过去即时返回的查询可能需要几分钟才能完成。过去需要几秒钟的查询现在可能会运行一个小时。
好消息是,你通常可以朝着另一个方向前进......至少在这种情况下。如果Bar
是nvarchar列并且您将baz
定义为varchar文字,那将是扩展转换,并且Sql Server将非常乐意只转换文字,仍然使用Bar列的索引。
当然,最好的选择是两个值具有相同的类型。
答案 1 :(得分:0)
OBJECT_ID设置为处理varchar或nvarchar,因此不会导致任何问题 http://technet.microsoft.com/en-us/library/ms190328.aspx
虽然OBJECT_ID没有问题。这不一定是全面的情况。在某些情况下,您需要小心。
/*This works*/
EXEC sp_executesql N'PRINT ''nvarchar Hello World'''
/*This doesn't*/
EXEC sp_executesql 'PRINT ''varchar Hello World'''
从理论上来说 对于真正像表名一样的nvarchar的东西,无论你是否需要,指定nvarchar文字可能是一个很好的习惯,进入并避免隐式类型转换的额外开销理论上会节省你很少的CPU时间但不是你会注意到的
这不是我保持特别好的习惯