我意识到,如果我的所有值都是固定宽度的,建议使用CHAR。但是,那又怎样?为了安全起见,为什么不为所有文本字段选择VARCHAR呢?
当前回答
在一些SQL数据库中,为了优化偏移量,VARCHAR将被填充到其最大大小,这是为了加速全表扫描和索引。
因此,与CHAR(200)相比,使用VARCHAR(200)并不会节省任何空间。
其他回答
在一些SQL数据库中,为了优化偏移量,VARCHAR将被填充到其最大大小,这是为了加速全表扫描和索引。
因此,与CHAR(200)相比,使用VARCHAR(200)并不会节省任何空间。
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还可以用来表示所有值都应该是相同的长度,例如,美国州缩写的列。
如果您和我一起工作,并且使用Oracle,我可能会让您在几乎所有情况下都使用varchar。char比varchar使用更少的处理能力的假设可能是正确的…现在……但是随着时间的推移,数据库引擎会变得更好,这种通用规则将成为未来的“神话”。
另一件事:我从未见过因为有人决定使用varchar而导致性能问题。你将更好地利用你的时间来编写好的代码(对数据库的调用更少)和高效的SQL(索引如何工作,优化器如何做出决策,为什么它比通常更快……)
最后一个想法:我在使用CHAR时看到过各种各样的问题,人们在“应该找‘’的时候找‘’,或者人们在应该找‘FOO(这里有一堆空格)’的时候找‘FOO’,或者人们没有去掉后面的空格,或者Powerbuilder在从Oracle过程中返回的值中添加2000个空格时出现了错误。
在计算列值实际所需的大小和为Varchar分配空间时,会有一些小的处理开销,因此如果您确实确定值总是多长,那么最好使用Char并避免命中。
推荐文章
- 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是图灵完备的吗?
- 如何检查表上持有哪些锁