对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

这篇具有很好参考价值的文章主要介绍了对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

开始之前:
设计某数据库表结构的过程中,收到了一个另外令人感到意外的建议:对于字符型数据类型,数据库里统一使用varchar(max)来存储,也就是所有字符数据类型都用varchar(max)字段类型,理由是ORM写代码方便?是的,你没有听错,为了ORM中写代码方便,所以建议数据库中字符型字段全部使用varchar(max)数据类型。这是中了ORM多深的毒!!!
对于这个问题,真的非常非常非常意外,有人竟然提出这种“建议”,我第一反应是想反问:为啥你上下班通勤,开个小轿车,而不是开个载重80吨的重型卡车?重型卡车想对小轿车又结实,又能走烂路,又能更多地载重,牵引力又大,空间也大,双肩包,电脑、钢筋、水泥都能装,所谓的兼容性更好,为什么不用重型卡车来上下班通勤?
 
刚好碰到一个对比VARCHAR(max) 与VARCHAR(n) 数据类型文章,于是就翻译了一下,以下为原文链接:
https://www.sqlshack.com/varcharmax-data-type-walkthrough-and-its-comparison-with-varcharn-in-sql-server/
 
以下是译文:
 
我见过SQL开发人员在设计表或临时表时使用varchar(max)数据。我们可能不确定数据长度,或者我们想消除字符串或二进制截断错误。每次使用都使用varchar(max)是否是一个好习惯?
我们可以为varchar(n)数据类型定义一个特定的范围,这是推荐的作法。为了了解这个数据类型,请阅读SQLvarchar(n)文章。
我们将在本文中讨论varchar max的使用及其影响,并与varchar(n)数据类型进行比较。
 

VARCHAR(max) SQL Server数据类型概述

SQL Server 2005引入了varchar(max)数据类型。它取代了大型blob对象Text、NText和Image数据类型。所有这些数据类型最多可存储2 GB的数据。
您可能知道SQL Server中的基本存储单位是页。SQL Server中的页大小为8 KB(8192字节),而且是固定的。在页上,SQL Server使用96个字节作为页头。我们可以在SQL Server中存储8096个字节(8192-96个字节)的数据。除此之外,页还包含行开销和行偏移,并留下8000个字节用于数据存储。因此,我们最多可以使用varchar(8000)数据类型存储8000个字节的数据(译者注:varchar(n)中n额最大值为8000,如果是nvarchar(n),n的最大值是4000)。
您可能会考虑使用varchar(max)数据类型来存储2 GB的数据,以解决字符串截断问题。
让我们创建一些具有不同varchar数据类型大小的示例表。我们还将创建一个具有varchar(max)数据类型的表。
CREATE TABLE dbo.Employee_varchar_2000
(id           INT IDENTITY PRIMARY KEY,
Col1 VARCHAR(2000)
);
 
CREATE TABLE dbo.Employee_Varchar_4500
(id           INT IDENTITY PRIMARY KEY,
Col1 VARCHAR(4500)
);
 
CREATE TABLE dbo.Employee_Varchar_8000
(id           INT IDENTITY PRIMARY KEY,
Col1 VARCHAR(8000)
);
 
CREATE TABLE dbo.Employee_Varchar_Max
(id           INT IDENTITY PRIMARY KEY,
Col1 VARCHAR(MAX)
);
让我们使用以下查询将记录插入到这些示例表中。
INSERT INTO Employee_varchar_2000 (Col1)
SELECT REPLICATE('A', 2000);
 
INSERT INTO Employee_varchar_4500 (Col1)
SELECT REPLICATE('A', 4500);
 
INSERT INTO Employee_varchar_8000 (Col1)
SELECT REPLICATE('A', 8000);
 
INSERT INTO Employee_varchar_max (Col1)
SELECT REPLICATE('A', 8000);
我们可以使用以下查询验证这些表中的数据长度。
Use SQLShackDemo
go

SELECT LEN(col1) AS columnlength
FROM Employee_varchar_2000;

SELECT LEN(col1) AS columnlength
FROM Employee_varchar_4500;

SELECT LEN(col1) AS columnlength
FROM Employee_varchar_8000;

SELECT LEN(col1) AS columnlength
FROM Employee_varchar_max;
现在,我们可以使用DMV sys.dm_db_index_physical_stats检查页面计数、行计数和分配单元等对象统计信息。
SELECT OBJECT_NAME([object_id]) AS TableName,
       alloc_unit_type_desc,
       record_count,
       page_count,
       round(avg_page_space_used_in_percent,0) as avg_page_space_used_in_percent ,
       min_record_size_in_bytes,
       max_record_size_in_bytes
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED')
WHERE OBJECT_NAME([object_id]) LIKE 'Employee_varchar%';
我们可以看到,所有表都包含分配单元IN_ROW_Data。SQL Server将所有数据存储在IN_ROW_Data分配单元中。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

我们不能在varchar(n)数据类型中插入超过8000字节的数据。如果尝试这样做,将得到以下错误消息。
INSERT INTO Employee_varchar_8000 (Col1)
SELECT REPLICATE('A', 8001);
Go
 
INSERT INTO Employee_varchar_8000 (Col1)
SELECT REPLICATE('A', 10000);
它成功插入数据,但将值截断为8000个字符。对于包含varchar(max)数据类型的Employee_varchar_max表也会发生类似的截断。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

我们需要将值转换为varchar(max)并插入超过8000个字符的长度。在尝试向Employee_varchar_8000表中插入记录时,我们得到了错误消息。
INSERT INTO Employee_varchar_8000 (Col1)
SELECT REPLICATE(CONVERT(VARCHAR(max), 'x'), 8001);

它成功地在Employee_varchar_max表中插入了记录。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

重新运行查询以检查分配单元。我们获取LOB_Data分配单元,以便在Employee_Varchar_Max表中存储超过8000字节的数据。我们在IN_Row_DATA分配单元中有一个指向此数据的指针。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

我们可以得出以下结论:

如果数据小于或等于8000字节,SQL Server使用IN_ROW_DATA页来存储varchar(max)数据类型的数据。
如果数据超过8000字节,SQL Server使用LOB_DATA页来存储varchar(max)数据类型的数据。

varchar(max)和varchar(n)数据类型之间的性能比较

让我们将10,000条记录插入到我们之前创建的每个表中。我们想检查数据插入时间。您可以使用ApexSQL Generate工具插入数据,而无需编写T-SQL代码。

在下面的屏幕截图中,您可以注意到以下几点。 译者注:我们无需关注原文作者使用的工具本身,只需要看他的测试方法和得到的结论

Employee_varchar_2000插入时间0.08秒
Employee_varchar_4500插入时间0.19秒
Employee_varchar_8000插入时间0.31秒
Employee_varchar_Max插入时间2.72秒

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

 文章来源地址https://www.toymoban.com/news/detail-775095.html

在 VARCHAR(N) and VARCHAR(MAX) 列上创建索引

作为DBA,您可能不会设计表。但是,需要在表上创建一个索引来提高查询的性能。
我们可以在持有varchar(n)数据类型的表的键列上创建索引。
CREATE INDEX IX_Employee_varchar_2000_1
ON dbo.Employee_varchar_2000(col1)
GO
当我们尝试对varchar(max)数据类型执行相同的操作时,会收到以下错误消息(译者注:SQLserver中varchar(max)类型字段不允许创建索引):
CREATE INDEX IX_Employee_varchar_max
ON dbo.Employee_varchar_max(col1)
GO

Msg 1919, Level 16, State 1, Line 23 Column ‘col1’ in table ‘dbo.Employee_varchar_max’ is of a type that is invalid for use as a key column in an index.
我们可以使用varchar(max)列作为索引中的包含列,但不能对这一列执行索引查找。它还需要额外的存储空间。因此,应避免使用varchar(max)数据类型创建索引。
 

执行计划(Execution plan)对比

让我们比较两个select语句的执行计划。

在第一个查询中,我们想从Employee_Varchar_2000表中检索数据并获取实际的执行计划。

在实际的执行计划中,我们可以看到一个非聚集索引查找操作符。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

如果我们使用varchar(max)数据类型运行相同的查询,它会使用聚集索引扫描操作符,并且根据表中的行数,它可能是一个资源密集型操作符。

select col1 from Employee_varchar_max where col1 like ‘xxxx%’

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

让我们使用SSMS的Compare Showplan选项比较执行计划。

要比较两个执行计划,右键单击其中一个执行计划并选择Save Execution Plan As,然后提供要保存该计划的路径。在另一个查询执行计划中,右键单击并选择Compare Showplan。它打开一个窗口,您可以在其中指定先前保存的执行计划的路径。在下面的屏幕截图中,您可以看到两个执行计划之间的比较。

1,对于相似的查询,varchar(max)数据类型的估计CPU成本更高
2,对于varchar(max),它使用聚集索引扫描操作符并扫描所有记录。您可以看到,估计的行数是10000行,而在varchar(2000)数据类型中,它使用索引查找操作符,估计的行数是1.96078行
3,估计的行大小4035 B大于varchar(max)中的1011 B,与varchar(2000)数据类型相比

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

译者注:这部分原作者想表达的是:对于varchar(max)类型字段,数据库优化器在编译SQL生成执行计划的时候会需要更多的CPU资源,同时对于数据行的预估也没有varchar(n)准确

varchar(max) and varchar(n) 数据类型的不同之处

varchar(max) varchar(n)
这种数据类型最多可以存储2gb的数据 这种数据类型最多可以存储8000字节的数据
它使用分配单元IN_ROW_Data最多8000字节的数据。如果数据大于8000字节,则使用LOB_Data页,并将其指针存储在IN_ROW_Data页中 它将数据存储在标准数据页中
不能在varchar(max)数据类型的键列上创建索引 可创建索引
不能压缩LOB数据 可压缩
LOB数据的数据检索和更新相对较慢 在varchar(n)数据类型中不会遇到这样的问题
 

总结

在本文中,我们演示了varchar(max)数据类型,并探讨了varchar(max)和varchar(n)数据类型之间的几个差异。您应该使用适当的数据类型。我们应该考虑数据库设计、性能、压缩和索引。您应该审查数据库中的数据类型,并在需要时进行适当的测试和更改。
 

 

笔者补充

varchar(max)和varchar(n)字段生成的执行计划差异

鉴于varchar(max)字段不支持创建索引,其实已经完全没有进一步做性能测试的必要了,为了把问题说清楚,那么就在没有索引的情况下继续对比测试下去,单纯地比较两种字段类型在生产执行计划时的差异。
进步一对比对比varchar(max)和varchar(n)对执行计划的影响,先创建一个测试环境。
create table sb_test1
(
    c1 int identity(1,1),
    c2 varchar(50),
    c3 varchar(50),
    c4 varchar(50),
    c5 varchar(50),
    c6 varchar(50),
    c7 varchar(50),
    c8 varchar(50),
    c9 varchar(50),
    c10 datetime2
);


create table sb_test2
(
    c1 int identity(1,1),
    c2 varchar(max),
    c3 varchar(max),
    c4 varchar(max),
    c5 varchar(max),
    c6 varchar(max),
    c7 varchar(max),
    c8 varchar(max),
    c9 varchar(max),
    c10 datetime2
);


declare @i int = 0;
begin tran
    while @i<1000000
    begin
        insert into sb_test1 values (newid(),newid(),newid(),newid(),newid(),newid(),newid(),newid(),sysdatetime())
        set @i = @i + 1;
    end
commit
go 10

insert into sb_test2 
select c2,c3,c4,c5,c6,c7,c8,c9,c10 from sb_test1 

以上新建两张表结构和数据一样的表,sb_test1表字段用varchar(50),sb_test2表字段用varchar(max),都是1000W行数据。

 

执行计划内存授予(memory grant)差异

1,对于同一个查询,执行计划的Memory Grant明显不一样,varchar(max)类型字段的表的执行计划内存(memory grant)明显要高很多。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

执行计划where筛选条件执行的差异

2,对于同一个查询,谓词predicate过滤的时机也不一样,varchar(n)可以再扫描的过程中实现谓词过滤(边扫描边过用where条件滤),而varchar(max)只能在将表扫描完之后,在内存中单独执行谓词过滤(完全扫描之后再用where条件过滤)

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

执行计划CPU消耗差异

3,对于同一个查询,执行结果中的的CPU资源消耗明显不一样(基于上述中的2,执行计划无法再扫描的时候进行谓词过滤),varchar(max)类型字段的表的查询要varchar(n)高2倍多。

对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型

再总结

关于varchar(n)和varchar(max)的不同点
1,存储方式不同
2,对所在表字段的操作开销不同
3,索引支持不同
即便是存储同样的内容,只要不超过8000个字节,在处理varchar(max)需要更多的资源,要不然varchar(n)或者char(n)就没有存在的意义了。

不单单是字符型数据,包括整型(tinyint,smallint,int,bigint),时间类型(date,time,smalldatetime,datetime,datetime2)等等,具体的类型选择是基于业务的,不是基于ORM好不好处理的问题。
错误的做法没有造成特别明显的问题,这并不是说明这就是可行的,而是是因为数据量没到,不要把错误的经验当成经验使用。

 

到了这里,关于对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SQL Server数据类型

    目录 一、数值型数据 二、货币型数据 三、字符型数据 四、日期/时间数据类型 1、Bigint。 可以存放从-263到263-1范围内的 整型数据 。以bigint数据类型存储的每个值占用8个字节,共64位,其中63位用于存储数字,1位用于表示正负。 2、Int 。也可以写作integer,可以存储从-231到

    2024年02月04日
    浏览(28)
  • SQL server 数据类型转换

    在 SQL Server 中, CONVERT  和  PARSE  函数可以用于将一个数据值从一种数据类型转换为另一种数据类型,它们与  CAST  函数一样是 SQL Server 中常见的数据类型转换函数。 CONVERT 函数 CONVERT  函数用于将一个数据值从一种数据类型转换为另一种数据类型。它的基本语法如下: 其

    2024年02月11日
    浏览(36)
  • 关于Sql server数据类型HierarchyID 数据类型用法和递归显示完整路径

    SQL Server 2008版本之后的新类型HierarchyID 不知道大家有没有了解, 该类型作为取代id, parentid的一种解决方案,让人非常惊喜。 官方给的案例浅显易懂,但是没有实现我想要的基本功能,树形结构中完整名称路径的展示。本文末尾是一个完整路径的样例,需要更多基本操作可以

    2024年03月13日
    浏览(29)
  • 解决sql server 不支持variant的数据类型

    博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的博客👦🏻 《java 面试题大全》 🍩惟余辈才疏学浅,临摹之作或有不妥之处,还请读者海涵指正。☕🍭 《MYSQL从入门到精通》数据库是开发者必会基础之一~ 🪁 吾期望此文有资助于尔,即使粗浅难及深广,亦备添少许微薄

    2024年02月09日
    浏览(32)
  • 【数据类型】C#和Sql Server、Mysql、Oracle等常见数据库的数据类型对应关系

    🏆🏆这是小5写的第二篇城市领跑者文章,一起为所在城市领跑助力吧! 🏆🏆在实际项目中,不管是用C#后端编程语言也好,还是Java后端编程语言,都可能会用到不同端的数据类型转换和对应关系 在 C# 和 SQL Server 之间,以下是一些最常用的数据类型对应关系: 编号 C#数据

    2024年02月11日
    浏览(42)
  • Oracle 19c 新特性|增加 VARCHAR2 数据类型的大小限制

    作者 | JiekeXu 来源 |公众号 JiekeXu DBA之路(ID: JiekeXu_IT) 如需转载请联系授权 | (个人微信 ID:JiekeXu_DBA) 大家好,我是 JiekeXu,很高兴又和大家见面了,今天和大家一起来学习 Oracle 19c 新特性,欢迎点击上方蓝字“JiekeXu DBA之路”关注我的公众号,标星或置顶,更多干货第一时间到

    2024年02月03日
    浏览(29)
  • 【数据库】sql server 中的sql语句--增删改查

    上面是要建立的数据库 下面是sql语句:  

    2024年02月05日
    浏览(38)
  • SQL Server中的不同数据删除方法

    在SQL Server中,有多种方法可以删除数据。无论是删除单个记录还是删除满足特定条件的多个记录,SQL Server提供了灵活且强大的功能来满足不同的需求。本文将介绍一些常用的SQL Server数据删除方法,并提供相应的源代码示例。 使用DELETE语句删除单个记录: DELETE语句用于删除

    2024年01月21日
    浏览(38)
  • 【SQL开发实战技巧】系列(二十):数据仓库中时间类型操作(进阶)获取季度开始结束时间以及如何统计非连续性时间的数据

    【SQL开发实战技巧】系列(一):关于SQL不得不说的那些事 【SQL开发实战技巧】系列(二):简单单表查询 【SQL开发实战技巧】系列(三):SQL排序的那些事 【SQL开发实战技巧】系列(四):从执行计划讨论UNION ALL与空字符串UNION与OR的使用注意事项 【SQL开发实战技巧】系列

    2024年02月02日
    浏览(56)
  • 【SQL Server】数据库开发指南(二)MSSQL数据库开发对于库、表、数据类型、约束等相关操作

    本系列博文还在更新中,收录在专栏:#MS-SQL Server 专栏中。 本系列文章列表如下: 【SQL Server】 Linux 运维下对 SQL Server 进行安装、升级、回滚、卸载操作 【SQL Server】数据库开发指南(一)数据库设计的核心概念和基本步骤 【SQL Server】数据库开发指南(二)MSSQL数据库开发对

    2023年04月09日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包