我意识到,如果我的所有值都是固定宽度的,建议使用CHAR。但是,那又怎样?为了安全起见,为什么不为所有文本字段选择VARCHAR呢?
当前回答
如果字段中的所有数据值长度相同,则CHAR占用的存储空间比VARCHAR少。现在,在2009年,800GB的数据库与810GB的数据库(如果您将varchar转换为CHARs)在所有用途和目的上是一样的,但对于短字符串(1或2个字符),CHAR仍然是行业的“最佳实践”。
现在,如果您查看大多数数据库提供的各种各样的数据类型,即使是整数(bit、tiny、int、bigint),也有理由选择其中一种。每次都简单地选择bigint实际上是对字段的目的和用途有点无知。如果一个字段只是以年为单位表示一个人的年龄,那么使用bigint就太夸张了。现在它不一定是“错误的”,但它不是有效的。
但这是一个有趣的争论,随着数据库的改进,可以说CHAR vs VARCHAR的相关性越来越小。
其他回答
Char更快一点,所以如果你知道一个列有一定的长度,就使用Char。例如,存储(M)ale/(F)emale/(U)nknown表示性别,或者存储2个字符表示美国的一个州。
我支持吉姆·麦基思的评论。
此外,如果您的表只有CHAR列,那么索引和全表扫描会更快。基本上,优化器将能够预测每条记录有多大,如果它只有CHAR列,而它需要检查每个VARCHAR列的大小值。
此外,如果您将VARCHAR列更新到比其先前内容更大的大小,则可能会强制数据库重新构建其索引(因为您强制数据库将记录物理地移动到磁盘上)。而对于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只是浪费空间。
希望这能有所帮助。 杰夫
我永远不会使用字符。我和很多人都有过这样的争论,他们总是提出令人厌倦的cliché char更快。我说,快多少?我们在这里讨论的是什么,毫秒,秒,如果是的话,是多少?你是在告诉我,因为有人声称它快了几毫秒,我们就应该在系统中引入大量难以修复的bug ?
这里有一些你会遇到的问题:
每个字段都将被填充,因此您最终得到的代码将永远到处都是RTRIMS。对于较长的字段来说,这也是一种巨大的磁盘空间浪费。
现在假设你有一个典型的例子,一个只有一个字符的char字段,但是这个字段是可选的。如果有人传递一个空字符串到这个字段,它就变成了一个空格。因此,当另一个应用程序/进程查询它时,如果不使用rtrim,它们将得到一个单独的空间。我们有xml文档,文件和其他程序,只显示一个空格,在可选字段和打破东西。
现在你要确保传递给char字段的是空值而不是空字符串。但这不是null的正确用法。这里是null的用法。假设您从供应商那里获得了一个文件
城市名字性别| |
鲍勃| |洛杉矶
如果没有指定性别,则在表中输入Bob、空字符串和Los Angeles。现在让我们假设你得到了文件,它的格式改变了,性别不再包括在内,而是在过去。
城市名称|
鲍勃|西雅图
好吧,现在由于性别不包括在内,我将使用null。Varchars毫无问题地支持这一点。
而夏尔则不同。你总是要发送null。如果你发送空字符串,你将得到一个包含空格的字段。
我可以继续在大约20年的开发过程中修复所有的错误。
如果字段中的所有数据值长度相同,则CHAR占用的存储空间比VARCHAR少。现在,在2009年,800GB的数据库与810GB的数据库(如果您将varchar转换为CHARs)在所有用途和目的上是一样的,但对于短字符串(1或2个字符),CHAR仍然是行业的“最佳实践”。
现在,如果您查看大多数数据库提供的各种各样的数据类型,即使是整数(bit、tiny、int、bigint),也有理由选择其中一种。每次都简单地选择bigint实际上是对字段的目的和用途有点无知。如果一个字段只是以年为单位表示一个人的年龄,那么使用bigint就太夸张了。现在它不一定是“错误的”,但它不是有效的。
但这是一个有趣的争论,随着数据库的改进,可以说CHAR vs VARCHAR的相关性越来越小。
推荐文章
- GROUP BY with MAX(DATE)
- 删除id与其他表不匹配的sql行
- 等价的限制和偏移SQL Server?
- 为什么我不能在DELETE语句中使用别名?
- 在SQL Server Management Studio中保存带有标题的结果
- "where 1=1"语句
- 如何选择一个记录和更新它,与一个单一的查询集在Django?
- 多语句表值函数vs内联表值函数
- 如何从Oracle的表中获取列名?
- NOLOCK提示在SELECT语句中的作用
- SQL OVER()子句-它什么时候有用,为什么有用?
- 如果字段在MySQL中为空,则返回0
- 我如何使用ROW_NUMBER()?
- SQL或者TSQL是图灵完备的吗?
- 如何检查表上持有哪些锁