2011-10-09 60 views
2

我正在使用SQL Server 2005/2008 Express数据库。对于varchar字段使用N字符串前缀(用于nvarchar字段)是否存在任何问题?SQL Server nvarchar用于varchar字段的N前缀

例如如果我有一个数据库字段:

CREATE TABLE [dbo].[posts](
    post_title varchar(30) 
) 

然后,我只插入ASCII数据,但与N前缀:

INSERT INTO [dbo].[posts] ([post_title]) VALUES (N'My Title'); 

问题就出现了,因为我想为UTF-8字符从PHP应用程序保存而我目前无法区分它保存的字段是varchar还是nvarchar。所以我只想假设所有的都是nvarchar,因为我只会尝试将ASCII字符保存到varchar字段。

+1

这表明你没有使用parametrised查询? –

+0

不,它使用CakePHP,它只是生成SQL,然后将其作为未参数化查询运行它 – icc97

+1

@Martin Smith:前一段时间我们注意到查询计划中没有转换。 By design http://sqlblog.com/blogs/paul_white/archive/2011/07/19/join-performance-implicit-conversions-and-residuals.aspx – gbn

回答

2

如果您将具有N前缀的字符串写入varchar字段,它将被隐式转换。没有其他开销,您可以安全地假设“一切都是nvarchar”

由于数据类型优先级,可能会比较nvarchar变量与varchar列存在问题。 varchar列将被转换,并且不会使用任何索引。

+0

感谢您的答案,我正在寻找 - 我会在10分钟内接受它!对于第二部分,你是说我可能会碰到'SELECT * FROM [posts] WHERE [post_title] = N'My Title''的问题,或者只有当我使用nvarchar变量时,例如在存储过程中 – icc97

+1

@ icc97:两种情况下,如果[post_title]是varchar。我没有安装SQL Server来验证你的内联SQL,所以它可能是优化器正确地解决这个问题。例如:http://sqlserverpedia.com/blog/sql-server-bloggers/indexes-and-convert_implicit/ – gbn

+1

谢谢。仅仅因为我不知道,我查了[数据类型优先](http://msdn.microsoft.com/en-us/library/ms190309.aspx),这是varchar转换为nvarchar [隐式]( http://msdn.microsoft.com/en-us/library/ms187928.aspx)(正如你所说,但现在我明白了一点)。除此之外,我通过在具有整数主键和varchar字段的表上运行一些检查来做了一个快速测试。无论在varchar字段上是否存在索引,它总是使用聚集主键索引来执行搜索。 – icc97

2

接受的答案是误导性的,但这部分是由于问题本身含糊不清(尽管可能不是故意)。

是的,任何Unicode字符串(即文字与N,或XMLN -prefixed变量前缀),当存储将隐式转换为8位ASCII一个CHAR/VARCHAR/TEXT(不要使用这一个!)领域。 但是,这在许多情况下可能是一个相当重要的区别,只有在U + 0000到U + 007F范围内的Unicode码点(即ASCII值0-127)才能保证正确转换。从U + 0080(即ASCII值128)开始的所有内容都可能会或可能不会进行转换,具体取决于所插入字段的整理所隐含的代码页。如果该排序规则的代码页没有该符号的映射,则代之以?

要找出代码页是究竟是什么,首先通过以下两种查询发现场的归类:

SELECT * FROM sys.columns WHERE [object_id] = OBJECT_ID(N'table_name'); 

-- OR: 

EXEC sp_help N'table_name'; 

然后你可以从整理发现代码页,使用:

SELECT COLLATIONPROPERTY('collation_name', 'CodePage'); 

然后,您可以在几个网站中的任何一个网站上找到一个图表,根据该代码页码显示您映射的内容。

排序规则不是按行排列的,它们是按字段排列的。因此,无论排序规则是什么,字段都会确定非Unicode字段的字符集(即CHAR/VARCHAR/TEXT)。

所以问题是:在问题中术语“ASCII”是什么意思?它在技术上仅指7位值(前128个;值0-127),但人们经常使用它来表示任何可以放入单个字节的内容,其中还包括扩展ASCII值(第128个值) 128 - 255),这取决于代码页。


对于周围有VARCHARNVARCHAR变量和文字的潜在问题(S):指标不会被忽略,但有一定的负面影响,而且变化的基础上VARCHAR列的排序规则。

如果列归类是SQL Server归类(即以SQL_开头,例如SQL_Latin1_General_CP1_CI_AS),那么您可以获得索引扫描,但不能搜索。

但是,如果列归类是Windows归类(即不是以SQL_开头,例如Latin1_General_100_CI_AS),那么您可以获得索引搜索。

下面的测试显示了这种行为:

-- DROP TABLE dbo.VarcharColumnIndex; 
CREATE TABLE dbo.VarcharColumnIndex 
(
    ID INT IDENTITY(1, 1) NOT NULL CONSTRAINT [PK_VarcharColumnIndex] PRIMARY KEY CLUSTERED, 
    SqlServerCollation VARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS, 
    WindowsCollation VARCHAR(50) COLLATE Latin1_General_100_CI_AS 
); 

CREATE NONCLUSTERED INDEX [IX_VarcharColumnIndex_SqlServerCollation] 
    ON dbo.VarcharColumnIndex ([SqlServerCollation]); 
CREATE NONCLUSTERED INDEX [IX_VarcharColumnIndex_WindowsCollation] 
    ON dbo.VarcharColumnIndex ([WindowsCollation]); 

INSERT INTO dbo.VarcharColumnIndex ([SqlServerCollation], [WindowsCollation]) 
    VALUES ('a', 'b'); 

DECLARE @a NVARCHAR(50) = N'a'; 
SELECT [SqlServerCollation] FROM dbo.VarcharColumnIndex WHERE [SqlServerCollation] = @a; 
-- Index Scan 

DECLARE @b NVARCHAR(50) = N'b'; 
SELECT [WindowsCollation] FROM dbo.VarcharColumnIndex WHERE [WindowsCollation] = @b; 
-- Index Seek 
+0

我在问题中做过状态“考虑到我只会尝试将ASCII字符保存到varchar字段”,因此接受的答案对此非常正确。你是对的 - 知道在这个范围之外会发生什么是很有用的 - 这不是我问的。 – icc97

+0

@ icc97是的,我从这个问题中理解了这种可能性,并在第一段和最后一段中提到了它。确切的“范围”没有指定,所以它可能意味着0-127或0-255,因为不同的人使用术语“ASCII”来表示。这就是为什么我不能从这个问题的措辞中推断出来的原因;-)其他有这个问题的人可能意思是0 - 255. –

+1

啊 - 好吧,这很有道理:) – icc97

相关问题