2011-10-09 59 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

相關問題