SQL2000 里的数据类型

作者: 来源: 日期:2008-4-8

(1)char、varchar、text 和 nchar、nvarchar、ntext

char 和 varchar 的长度都在 1 到 8000 之间,它们的区别在于 char 是定长字符数据,而varchar是变长字符数据。所谓定长就是长度固定的,当输入的数据长度没有达到指定的长度时将自动以英文空格在其后面填充,使长度达到相应的长度;而变长字符数据则不会以空格填充。text 存储可变长度的非 Unicode 数据,最大长度为 2^31-1(2,147,483,647) 个字符。

后面三种数据类型和前面的相比,从名称上看只是多了个字母"n",它表示存储的是 Unicode 数据类型的字符。写过程序的朋友对 Unicode 应该很了解。字符中,英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode 字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。nchar、nvarchar 的长度是在1到4000之间。和char、varchar 比较:nchar、nvarchar 则最多存储 4000 个字符,不论是英文还是汉字;而 char、varchar 最多能存储 8000 个英文,4000 个汉字。可以看出使用 nchar、nvarchar 数据类型时不用担心输入的字符是英文还是汉字,较为方便,但在存储英文时数量上有些损失。

(2)datetime和smalldatetime

  • datetime:从1753年1月1日到9999年12月31日的日期和时间数据,精确到百分之三秒。
  • smalldatetime:从1900年1月1日到2079年6月6日的日期和时间数据,精确到分钟。

(3)bitint、int、smallint、tinyint和bit

  • bigint:从-2^63(-9223372036854775808) 到 2^63-1(9223372036854775807) 的整型数据。
  • int:从-2^31(-2,147,483,648) 到 2^31-1(2,147,483,647) 的整型数据。
  • smallint:从-2^15(-32,768) 到 2^15-1(32,767) 的整数数据。
  • tinyint:从 0 到 255 的整数数据。
  • bit:1 或 0 的整数数据。

(4)decimal 和 numeric

这两种数据类型是等效的。都有两个参数:p(精度)和s(小数位数)。p 指定小数点左边和右边可以存储的十进制数字的最大个数,p 必须是从 1 到38 之间的值。s 指定小数点右边可以存储的十进制数字的最大个数,s 必须是从0到p之间的值,默认小数位数是 0。

(5)float 和 real

  • float:从 -1.79^308 到 1.79^308 之间的浮点数字数据。
  • real:从 -3.40^38 到 3.40^38 之间的浮点数字数据。在 SQL Server 中,real 的同义词为 float(24)。

以上内容为《SQL Server 中易混淆的数据类型》,首发于蓝色理想。编者注。

数据库定义到 char 类型的字段时,不知道大家是否会犹豫一下,到底选 char、nchar、varchar、nvarchar、text、ntext 中哪一种呢?结果很可能是两种,一种是节俭人士的选择:最好是用定长的,感觉比变长能省些空间,而且处理起来会快些,无法定长只好选用定长,并且将长度设置尽可能地小;另一种是则是觉得无所谓,尽量用可变类型的,长度尽量放大些。

鉴于现在硬件像萝卜一样便宜的大好形势,纠缠这样的小问题实在是没多大意义,不过如果不弄清它,总觉得对不起劳累过度的 CPU 和硬盘。

下面开始了(以下说明只针对 SqlServer 有效):

1、当使用非 unicode 时慎用以下这种查询:select f from t where f = N'xx'

原因:无法利用到索引,因为数据库会将f先转换到 unicode 再和 N'xx' 比较。

2、char 和相同长度的 varchar 处理速度差不多(后面还有说明)

3、varchar 的长度不会影响处理速度!!!(看后面解释)(作者可能想表达这样的意思:设定的长度不会影响处理速度,影响处理速度的是实际的存储长度,因为一条记录占用的空间越大,一个数据页存储的记录就越少,查询时翻页就越频繁。编者注。)

4、索引中列总长度最多支持总为 900 字节,所以长度大于 900 的 varchar、char 和大于 450 的 nvarchar,nchar 将无法创建索引。

5、text、ntext 上是无法创建索引的。

6、O/R Mapping 中对应实体的属性类型一般是以 string 居多,用 char[] 的非常少,所以如果按 mapping 的合理性来说,可变长度的类型更加吻合。

7、一般基础资料表中的 name 在实际查询中基本上全部是使用 like '%xx%' 这种方式,而这种方式是无法利用索引的,所以如果对于此种字段,索引建了也白建。(like 'xx%' 则可以使用索引。编者注。)

8、其它一些像 remark 的字段则是根本不需要查询的,所以不需要索引。

9、varchar 的存放和 string 是一样原理的,即 length 这种方式,所以varchar 的长度和它实际占用空间是无关的。(作者可能想表达这样的意思:varchar(1000) 并不一定就会占用 1000 的空间,其实际占用空间得根据其存储的内容来获得。编者注。)

10、对于固定长度的字段,是需要额外空间来存放 NULL 标识的,所以如果一个char字段中出现非常多的 NULL,那么很不幸,你的占用空间比没有 NULL 的大(但这个大并不是大太多,因为 NULL 标识是用 bit 存放的,可是如果你一行中只有你一个 NULL 需要标识,那么你就白白浪费 1byte 空间了,罪过罪过!),这时候,你可以使用特殊标识来存放,如:'NV'。

11、同上,所以对于这种 NULL 查询,索引是无法生效的,假如你使用了 NULL 标识替代的话,那么恭喜你,你可以利用到索引了。

12、char 和 varchar 的比较成本是一样的,现在关键就看它们的索引查找的成本了,因为查找策略都一样,因此应该比较谁占用空间小。在存放相同数量的字符情况下,如果数量小,那么 char 占用长度是小于 varchar 的,但如果数量稍大,则 varchar 完全可能小于 char,而且要看实际填充数值的充实度,比如说 varchar(3) 和 char(3),那么理论上应该是 char 快了,但如果是 char(10)和 varchar(10),充实度只有 30% 的情况下,理论上就应该是 varchar 快了。因为 varchar 需要额外空间存放块长度,所以只要 length(1-fillfactor) 大于这个存放空间(好像是 2 字节),那么它就会比相同长度的 char 快了。

13、nvarchar 比 varchar 要慢上一些,而且对于非 unicode 字符它会占用双倍的空间,那么这么一种类型推出来是为什么呢?对,就是为了国际化,对于 unicode 类型的数据,排序规则对它们是不起作用的,而非 unicode 字符在处理不同语言的数据时,必须指定排序规则才能正常工作,所以 n 类型就这么一点好处。

总结陈词

  1. 如果数据量非常大,又能 100% 确定长度且保存只是 ANSI 字符,那么 char;
  2. 能确定长度又不一定是 ANSI 字符或者,那么用 nchar;
  3. 不确定长度,要查询且希望利用索引的话,用 nvarchar 类型吧,将它们设到 400;
  4. 不查询的话没什么好说的,用 nvarchar(4000);
  5. 性格豪爽的可以只用 3 和 4,偶尔用用 1,毕竟这是一种额外说明,等于告诉别人说,我一定需要长度为 X 位的数据。

这样一来,生活是不是变成美好多了?如果还有没明白的,那么还是省点钱去买萝卜吧。

目前,大多数数据库设计的查询速度瓶颈在于表结构、字段类型、索引等的不合理。编者注。

相关文章