我意识到,如果我的所有值都是固定宽度的,建议使用CHAR。但是,那又怎样?为了安全起见,为什么不为所有文本字段选择VARCHAR呢?


当前回答

如果您和我一起工作,并且使用Oracle,我可能会让您在几乎所有情况下都使用varchar。char比varchar使用更少的处理能力的假设可能是正确的…现在……但是随着时间的推移,数据库引擎会变得更好,这种通用规则将成为未来的“神话”。

另一件事:我从未见过因为有人决定使用varchar而导致性能问题。你将更好地利用你的时间来编写好的代码(对数据库的调用更少)和高效的SQL(索引如何工作,优化器如何做出决策,为什么它比通常更快……)

最后一个想法:我在使用CHAR时看到过各种各样的问题,人们在“应该找‘’的时候找‘’,或者人们在应该找‘FOO(这里有一堆空格)’的时候找‘FOO’,或者人们没有去掉后面的空格,或者Powerbuilder在从Oracle过程中返回的值中添加2000个空格时出现了错误。

其他回答

Char更快一点,所以如果你知道一个列有一定的长度,就使用Char。例如,存储(M)ale/(F)emale/(U)nknown表示性别,或者存储2个字符表示美国的一个州。

当使用varchar值时,SQL Server每行需要额外的2个字节来存储关于该列的一些信息,而如果使用char则不需要 所以除非你

NChar或Char是否比它们的var替代品表现更好?

好问题。在某些情况下,简单的答案是肯定的。让我们看看这是否可以解释。

Obviously we all know that if I create a table with a column of varchar(255) (let's call this column myColumn) and insert a million rows but put only a few characters into myColumn for each row, the table will be much smaller (overall number of data pages needed by the storage engine) than if I had created myColumn as char(255). Anytime I do an operation (DML) on that table and request alot of rows, it will be faster when myColumn is varchar because I don't have to move around all those "extra" spaces at the end. Move, as in when SQL Server does internal sorts such as during a distinct or union operation, or if it chooses a merge during it's query plan, etc. Move could also mean the time it takes to get the data from the server to my local pc or to another computer or wherever it is going to be consumed.

但是使用varchar会有一些开销。SQL Server必须使用一个双字节指示器(开销),在每一行上,知道特定行的myColumn中有多少字节。造成问题的不是额外的2个字节,而是必须“解码”myColumn中每一行的数据长度。

In my experiences it makes the most sense to use char instead of varchar on columns that will be joined to in queries. For example the primary key of a table, or some other column that will be indexed. CustomerNumber on a demographic table, or CodeID on a decode table, or perhaps OrderNumber on an order table. By using char, the query engine can more quickly perform the join because it can do straight pointer arithmetic (deterministically) rather than having to move it's pointers a variable amount of bytes as it reads the pages. I know I might have lost you on that last sentence. Joins in SQL Server are based around the idea of "predicates." A predicate is a condition. For example myColumn = 1, or OrderNumber < 500.

因此,如果SQL Server正在执行一个DML语句,而谓词或被连接的“键”是一个固定长度(char),查询引擎不需要做大量的工作来匹配从一个表到另一个表的行。它不需要找出数据在行中有多长,然后沿着字符串找到结尾。所有这些都需要时间。

现在请记住,这很容易被糟糕地执行。我曾在在线系统中看到过用char作为主键字段。宽度必须保持较小,即char(15)或其他合理的值。它在在线系统中工作得最好,因为您通常只检索或上传少量行,因此必须“rtrim”结果集中的尾随空格,这是一项微不足道的任务,而不必将一个表中的数百万行连接到另一个表中的数百万行。

在在线系统上,CHAR比varchar更有意义的另一个原因是它减少了页面分割。通过使用char,你实际上是在“保留”(和浪费)这个空间,所以如果一个用户后来把更多的数据放到那个列中,SQL已经为它分配了空间。

使用CHAR的另一个原因与第二个原因类似。如果程序员或用户对数百万行进行“批处理”更新,例如在注释字段中添加一些句子,您不会在半夜接到DBA的电话,询问为什么他们的驱动器已满。换句话说,它导致数据库规模的增长更加可预测。

以上就是联机(OLTP)系统从char优于varchar中获益的3种方式。我很少在仓库/分析/OLAP场景中使用char,因为通常你有太多的数据,所有这些char列加起来会浪费大量的空间。

请记住,char会使您的数据库更大,但大多数备份工具都有数据压缩,因此您的备份往往与使用varchar时的大小相同。例如LiteSpeed或RedGate SQL Backup。

另一个用途是在为将数据导出到固定宽度文件而创建的视图中。假设我必须将一些数据导出到一个平面文件中以供主机读取。它是固定宽度(没有分隔)。我喜欢将数据以varchar的形式存储在“staging”表中(从而在数据库中消耗更少的空间),然后使用一个视图将所有内容CAST为它的char等效值,其长度对应于该列的固定宽度的宽度。例如:

create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )

insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)

create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))

SELECT * from vwStagingTable

This is cool because internally my data takes up less space because it's using varchar. But when I use DTS or SSIS or even just a cut and paste from SSMS to Notepad, I can use the view and get the right number of trailing spaces. In DTS we used to have a feature called, damn I forget I think it was called "suggest columns" or something. In SSIS you can't do that anymore, you have to tediously define the flat file connection manager. But since you have your view setup, SSIS can know the width of each column and it can save alot of time when building your data flow tasks.

所以底线是……使用varchar。使用char的原因很少,而且仅仅是出于性能方面的考虑。如果您有一个有数亿行的系统,如果谓词是确定性的(char),您将看到一个显著的差异,但对于大多数系统来说,使用char只是浪费空间。

希望这能有所帮助。 杰夫

早期性能优化和使用最佳实践类型的规则之间存在差异。如果创建的新表中总是有固定长度的字段,那么使用CHAR是有意义的,在这种情况下应该使用它。这不是早期优化,而是实现经验法则(或最佳实践)。

即-如果你有一个2字母的状态字段,使用CHAR(2)。如果您有一个包含实际州名的字段,请使用VARCHAR。

我会选择varchar,除非列存储固定的值,如美国州代码-这总是2个字符长,有效的美国州代码列表不经常改变:)。

在其他情况下,甚至像存储哈希密码(固定长度),我会选择varchar。

为什么——char类型的列总是用空格填充,这使得列my_column定义为char(5),值为'ABC'在比较中:

my_column = 'ABC' -- my_column stores 'ABC  ' value which is different then 'ABC'

假的。

这个特性可能会在开发过程中导致许多恼人的bug,并使测试更加困难。