SQL Server char nchar varchar nvarchar的区别

SQL Server char nchar  varchar nvarchar的区别

 

今天在论坛里看到有人激烈讨论这几个数据类型的区别跟实际使用情况,很多人都搞不清楚究竟哪个场景使用哪个数据类型

具体的编码方式:就是存储到电脑硬盘里面的表示方式,读到内存的时候实际上不管在电脑硬盘里是什么编码方式,在内存里通通都是unicode,个人理解,就像mssql存储到硬盘实际上是GBK编码,但是mssql2017要增加utf-8编码,Python文件要声明utf-8否则在Windows上的Python文件放到Linux会乱码

nvarchar    每个字段都加上2个字节的行偏移,而且每个字符占用两个字节(GBK编码一个字符占用两个字节),即使用不到两个字节都占用两个字节
nchar         每个字符占用两个字节(GBK编码一个字符占用两个字节)
如果是UTF-8编码,一个字符占用三个字节

所以,GBK编码对比UTF-8编码更节省存储空间

 

https://www.cnblogs.com/leomei91/p/7685797.html
在python中,unicode是内存编码集,一般我们将数据存储到文件时,需要将数据先编码为其他编码集,比如utf-8、gbk再保存到文件中

 

 

现在就摘录一下sql2005联机丛书里的关于这几个数据类型的解释

 

字符数据类型(nchar 长度固定,nvarchar 长度可变)和 Unicode 数据使用 UNICODE UCS-2 字符集。

nchar [ ( n ) ]

n 个字符的固定长度的 Unicode 字符数据。n 值必须在 1 到 4,000 之间(含),n指的是字符的长度。存储大小为两倍 n 字节,存储大小为8000字节,单位是字节,固定字节大小的前提下(8000字节)所存储的字符个数由排序规则/字符集而定,。nchar 的 SQL-2003 同义词为 national char 和 national character。

由于存储的是Unicode数据,所以字符数不等于字节数,可能多个字节只能存储一个字符

 

nvarchar [ ( n | max ) ]

可变长度 Unicode 字符数据。n 值在 1 到 4,000 之间(含),n指的是字符的长度。max 指示最大存储大小为 2^31-1 字节。存储大小是所输入字符个数的两倍 + 2 个字节 8002字节,单位是字节,固定字节大小的前提下(8000字节)所存储的字符个数由排序规则/字符集而定。所输入数据的长度可以为 0 个字符。nvarchar 的 SQL-2003 同义词为 national char varying 和 national character varying。

由于存储的是Unicode数据,所以字符数不等于字节数,可能多个字节只能存储一个字符

备注 如果没有在数据定义或变量声明语句中指定 n,则默认长度为 1。如果没有使用 CAST 函数指定 n,则默认长度为 30。

如果列数据项的大小可能相同,请使用 nchar。

如果列数据项的大小可能差异很大,请使用 nvarchar。

sysname 是系统提供的用户定义数据类型,除了不以为零外,在功能上与 nvarchar(128) 相同。sysname 用于引用数据库对象名

 

 

固定长度或可变长度的字符数据类型。

char [ ( n ) ]

固定长度,非 Unicode 字符数据,长度为 n 个字节。n 的取值范围为 1 至 8,000,存储大小是 n 个字节 ,由于只能存储ASCII数据,所以字符数等于字节数。char 的 SQL 2003 同义词为 character。

varchar [ ( n | max ) ]

可变长度,非 Unicode 字符数据。n 的取值范围为 1 至 8,000。max 指示最大存储大小是 2^31-1 个字节。存储大小是输入数据的实际长度加 2 个字节

n 的取值范围为 1 至 8,000,存储大小是 n 个字节 ,由于只能存储ASCII数据,所以字符数等于字节数

可变长度的偏移阵列  VarOffset   2*VarCount(每一列都要另外加上2个自己的偏移量)。所输入数据的长度可以为 0 个字符。SQL-2003 中的 varchar 就是 char varying 或 character varying。

备注 如果未在数据定义或变量声明语句中指定 n,则默认长度为 1。如果在使用 CAST 和 CONVERT 函数时未指定 n,则默认长度为 30。

将为使用 char 或 varchar 的对象指派数据库的默认排序规则,除非使用 COLLATE 子句指派了特定的排序规则。该排序规则控制用于存储字符数据的代码页。

如果站点支持多语言,请考虑使用 Unicode nchar 或 nvarchar 数据类型,以最大限度地消除字符转换问题。如果使用 char 或 varchar,建议执行以下操作:

如果列数据项的大小一致,则使用 char。

如果列数据项的大小差异相当大,则使用 varchar。

如果列数据项大小相差很大,而且大小可能超过 8,000 字节,请使用 varchar(max)。

本人测试了一下这几个数据类型的区别,以下是测试脚本跟结果:

 1 DECLARE @a CHAR(6)
 2 SET @a='您啊啊啊啊是'
 3 PRINT 'char:'+@a
 4 
 5 DECLARE @b CHAR(6)
 6 SET @b='abcdefg'
 7 PRINT 'char:'+@b
 8 
 9 DECLARE @c CHAR(6)
10 SET @c='123456'
11 PRINT 'char:'+@c
12 -----------------------
13 
14 DECLARE @d NCHAR(6)
15 SET @d=N'您啊啊啊啊是'
16 PRINT 'nchar:'+@d
17 
18 DECLARE @e NCHAR(6)
19 SET @e=N'abcdefg'
20 PRINT 'nchar:'+@e
21 
22 DECLARE @f NCHAR(6)
23 SET @f=N'123456'
24 PRINT 'nchar:'+@f
25 ------------------------------
26 
27 DECLARE @g VARCHAR(6)
28 SET @g='您啊啊啊啊是'
29 PRINT 'varchar:'+@g
30 
31 DECLARE @h VARCHAR(6)
32 SET @h='abcdefg'
33 PRINT 'varchar:'+@h
34 
35 DECLARE @i VARCHAR(6)
36 SET @i='123456'
37 PRINT 'varchar:'+@i
38 --------------------------------
39 DECLARE @j NVARCHAR(6)
40 SET @j=N'您啊啊啊啊是'
41 PRINT 'nvarchar:'+@j
42 
43 DECLARE @k NVARCHAR(6)
44 SET @k=N'abcdefg'
45 PRINT 'nvarchar:'+@k
46 
47 DECLARE @l NVARCHAR(6)
48 SET @l=N'123456'
49 PRINT 'nvarchar:'+@l

 

结果:

char:您啊啊
char:abcdef
char:123456
nchar:您啊啊啊啊是
nchar:abcdef
nchar:123456
varchar:您啊啊
varchar:abcdef
varchar:123456
nvarchar:您啊啊啊啊是
nvarchar:abcdef
nvarchar:123456

 

最后说一下,NCHAR  NVARCHAR都要在字符前面加N,避免出现乱码!!

 

nvarchar 、nchar、char、varchar实际占用存储空间比较

nvarchar [ ( n | max ) ]:unicode格式编码保存字符,所以每个字符占用两个字节(GBK编码一个字符占用两个字节) ,加上2个字节的行偏移 最大4000

nchar [ ( n ) ]:             unicode格式编码保存字符,所以每个字符占用两个字节(GBK编码一个字符占用两个字节)  最大4000

char [ ( n ) ]:               是多少就是多少 最大8000

varchar [ ( n | max ) ]:  加上2个字节的行偏移 最大8000

 

就是说大家的实际占用存储空间都是8000字节的前提下

nvarchar    每个字段都加上2个字节的行偏移,而且每个字符占用两个字节(GBK编码一个字符占用两个字节),即使用不到两个字节都占用两个字节

nchar         每个字符占用两个字节(GBK编码一个字符占用两个字节),即使用不到两个字节都占用两个字节

varchar      每个字段都加上2个字节的行偏移

char          每个字符占用一个字节

 

 

SQL Server不能像Oracle那样分别设置数据库字符集和国家字符集,而是通过设置排序规则指定数据库字符集和国家字符集

SQL Server的排序规则规定了数据库字符集的代码页(国家字符集统一使用unicode编码,不需要另外设置)
Chinese_PRC_CI_AS:基于中文排序,不区分大小写,区分重音字符

中文Windows环境下,服务器默认排序规则为Chinese_PRC_CI_AS

CREATE DATABASE testcol COLLATE Latin1_General_CI_AS

USE testcol
CREATE TABLE tt2 (id INT,
a CHAR(1),  iso_1
b VARCHAR(1), iso_1
c NCHAR(1),  UNICODE
d NVARCHAR(1))  UNICODE

USE [testcol]
SELECT [TABLE_NAME],[COLUMN_NAME],[COLLATION_NAME],[CHARACTER_SET_NAME] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME]='tt2' AND [TABLE_CATALOG]='testcol'


---------------------------------------------------------------------------------------------------------

CREATE DATABASE test COLLATE Chinese_PRC_CI_AS
CREATE TABLE tt9(
id INT ,
a CHAR(6),   cp936
b NCHAR(6),   UNICODE
c VARCHAR(6),  cp936
d NVARCHAR(7))   UNICODE

 
USE [test]
SELECT [TABLE_NAME],[COLUMN_NAME],[COLLATION_NAME],[CHARACTER_SET_NAME] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME]='tt9' AND [TABLE_CATALOG]='test'

 

char和varchar用的是cp936,nchar和nvarchar用的是UNICODE,cp936是Windows系统对GBK1.0实现

 

https://learn.microsoft.com/zh-cn/sql/relational-databases/collations/collation-and-unicode-support?view=sql-server-ver16#Supplementary_Characters
从sqlserver2019开始
把服务器或者数据库或字段的排序规则更改为 xxxUTF8 这种带有UTF8 后缀的,那么CHAR(n) 和 VARCHAR(n) 将使用UTF-8 编码
例如: LATIN1_GENERAL_100_CI_AS_SC 更改为 LATIN1_GENERAL_100_CI_AS_SC_UTF8

注意:
UTF8 编码只能应用于CHAR(n) 和 VARCHAR(n) 数据类型,并且要更改排序规则才能使用(UTF-8 仅适用于支持增补字符的 Windows 排序规则)
NCHAR(n) 和 NVARCHAR(n) 数据类型编码保持不变,同样使用 UCS-2 或 UTF-16编码

UTF-8 编码和UTF-16编码 在表示中文时候,使用的存储空间都一样,所以支持UTF-8 编码真的是多此一举

 

posted @ 2012-08-31 20:44  桦仔  阅读(3762)  评论(0编辑  收藏  举报