SQL Server 表变量和临时表系列之概念篇

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: # 问题引入 “菜鸟啊,最近我看到阿里云开发者论坛的数据库RDS中有人在提SQL Server表变量和临时表如何选择的问题,你去深入探讨下这个问题吧,解答解答他们的疑惑吧”,老鸟又开始为菜鸟找活干了。 “鸟哥啊,关于表变量和临时表使用选择的问题啊,向来行业里争论不休,我比较担心我们的观点被人家拍砖啊”。 “鸟啊,有争论才说明这个问题有价值啊,所以我们才更应该去弄清楚,道明白啊”。反正老鸟总会

问题引入

“菜鸟啊,最近我看到阿里云开发者论坛的数据库RDS中有人在提SQL Server表变量和临时表如何选择的问题,你去深入探讨下这个问题吧,解答解答他们的疑惑吧”,老鸟又开始为菜鸟找活干了。
“鸟哥啊,关于表变量和临时表使用选择的问题啊,向来行业里争论不休,我比较担心我们的观点被人家拍砖啊”。
“鸟啊,有争论才说明这个问题有价值啊,所以我们才更应该去弄清楚,道明白啊”。反正老鸟总会找到合适的理由。
“那好吧,要把这个问题要刨根问底,我们需要分四篇文章来把这个问题理清楚。”,菜鸟掰着手指头就数了出来:
 表变量和临时表基本概念
 表变量和临时表的对比
 表变量和临时表认知误区
 表变量和临时表的选择

什么是表变量

关于什么是SQL Server的表变量,我们分别从表变量的定义、表变量的作用和表变量的使用三个角度来看看什么是表变量。

表变量定义

表变量,是微软至SQL Server 2000以来引入的概念,从名称我们就可以很容易看出,表变量本质是一个变量,只是它具有了正式表对象的很多属性。比如:它有表字段、字段数据类型、字段宽度、主键、唯一约束、NULL、NOT NULL约束、CHECK和DEFAULT约束。但是,表变量不支持约束命名,不支持索引,不支持外键,不支持表变量定义后的任何表变量结构的修改,仅可做数据的DML操作。

表变量的作用

当我们需要在当前会话临时缓存少量的中间数据结果集,供当前会话多次使用这同一数据集或者同一数据结果集的一部分时,我们可以考虑使用表变量,表变量中的数据是缓存在内存中(大部分情况下如此,也有极少情况例外,我们后面的文章会讲到)。注意这里是少量数据集,不是大量结果集,如果非要给一个参照经验值的话,个人建议是最好不要超过10万条数据记录,所占的空间大小不要超过100MB。

表变量的使用

关于表变量作用,在此我们以一个例子来说明。在这个例子中,我们定义了一个表变量来暂时存放商品的基本属性信息,然后INSERT了三条数据,紧接着对其中一条数据做UPDATE操作,再接着DELETE了一条数据,最后我们SELECT了整个表变量存放的数据。

USE tempdb
GO

DECLARE
    @tb_table TABLE(
RowID INT IDENTITY(1,1) NOT NULL PRIMARY KEY
,ProductName NVARCHAR(50) NOT NULL UNIQUE
,Length DECIMAL(4,2) NOT NULL CHECK(Length>0.0)
,Windth DECIMAL(4,2) NOT NULL CHECK(Windth>0.0)
,Height DECIMAL(4,2) NOT NULL CHECK(Height>0.0)
,Dimension AS (Length * Windth * Height)
,Indate DATETIME NOT NULL  DEFAULT(GETDATE())
);

INSERT INTO @tb_table(ProductName, Length, Windth, Height) VALUES('A', 0.1, 0.2, 0.3);
INSERT INTO @tb_table(ProductName, Length, Windth, Height) VALUES('B', 0.4, 0.5, 0.6);
INSERT INTO @tb_table(ProductName, Length, Windth, Height) VALUES('C', 0.7, 0.8, 0.9);

UPDATE A
SET Length = 2.5
FROM @tb_table AS A
WHERE RowID = 1
;

DELETE TOP(1) A
FROM @tb_table AS A
WHERE RowID = 2;

SELECT * FROM @tb_table;

从这个例子,我们看到了表变量所具有的正式表对象的属性,表变量是如何定义的,以及DML操作,在当前会话结束后,表变量会被SQL Server自动回收。
这里需要特别提醒下,SQL Server系统不允许我们像正式表对象那样对约束进行显示命名,SQL Server会报告错误。比如,定义表变量代码:

USE tempdb
GO
DECLARE
    @tb_table TABLE(
RowID INT IDENTITY(1,1) NOT NULL PRIMARY KEY
,ProductName NVARCHAR(50) NOT NULL UNIQUE
,Length DECIMAL(8,2) NOT NULL
,Windth DECIMAL(8,2) NOT NULL
,Height DECIMAL(8,2) NOT NULL
,Indate DATETIME NOT NULL  CONSTRAINT DF_tbTable DEFAULT(GETDATE())
,CONSTRAINT CK_Windth CHECK(Windth>0.0)
);

报错信息如下:

Msg 156, Level 15, State 1, Line 10
Incorrect syntax near the keyword 'CONSTRAINT'.

什么是临时表

在看完什么是表变量以后,我们还是分别从临时表定义、临时表的作用和临时表的使用三个角度来看看什么是SQL Server的临时表。

临时表定义

SQL Server的临时表是一种特殊的表,表名字是以#或者##打头。无论临时表在哪个数据库下创建,SQL Server均把临时表结构信息和数据存储在Tempdb数据库下。
以#打头的临时表称为局部临时表,这种类型的临时表仅当前进程可见,其他进程不可访问,生命周期会随着当前连接进程的关闭而消亡。
以##打头的临时表称为全局,此类型的临时表对所有进程可见,当前进程和其他进程均可访问,生命周期是所有使用到全局临时表的连接完全关闭后,临时表消亡。

临时表的作用

临时表的作用和表变量类似,均是用于暂时缓存数据。临时表中的数据会被储存在Tempdb的物理文件磁盘上,当需要数据读取时,SQL Server会将临时表中数据从磁盘文件读入SQL Server Buffer Pool中,然后返回给客户端。因此,临时表对数据的存储和读取会有物理的IO Write和IO Read的。临时表相较于表变量可以存储稍微大量一些的数据,比如数据量超过10万条记录数,数据空间占用量超过100MB。但是,如果经常有类似的临时表使用场景时,建议对Tempdb数据库做性能优化相关的配置工作。

临时表的使用

为了和表变量形成对比,我特意将表结构和数据保持一致,不同的地方在于,我们可以对约束进行显示指定命名,可以创建索引。在次,为了看清楚局部临时表和全局临时表的区别,我们也创建了一个全局临时表。

USE tempdb
GO
IF OBJECT_ID('tempdb..#tb_table','U') IS NOT NULL
    DROP TABLE #tb_table
GO
CREATE TABLE #tb_table(
RowID INT IDENTITY(1,1) NOT NULL PRIMARY KEY
,ProductName NVARCHAR(50) NOT NULL UNIQUE
,Length DECIMAL(4,2) NOT NULL CHECK(Length>0.0)
,Windth DECIMAL(4,2) NOT NULL
,Height DECIMAL(4,2) NOT NULL CHECK(Height>0.0)
,Dimension AS (Length * Windth * Height)
,Indate DATETIME NOT NULL  CONSTRAINT DF_tbTable DEFAULT(GETDATE())
,CONSTRAINT CK_Windth CHECK(Windth>0.0)
);

CREATE INDEX IX_ProductName
ON #tb_table(ProductName);
GO

INSERT INTO #tb_table(ProductName, Length, Windth, Height) VALUES('A', 0.1, 0.2, 0.3);
INSERT INTO #tb_table(ProductName, Length, Windth, Height) VALUES('B', 0.4, 0.5, 0.6);
INSERT INTO #tb_table(ProductName, Length, Windth, Height) VALUES('C', 0.7, 0.8, 0.9);

IF OBJECT_ID('tempdb..##tb_table','U') IS NOT NULL
    DROP TABLE ##tb_table
GO
SELECT * 
    INTO ##tb_table
FROM #tb_table;

UPDATE A
SET Length = 2.5
FROM #tb_table AS A
WHERE RowID = 1
;

DELETE TOP(1) A
FROM #tb_table AS A
WHERE RowID = 2;

SELECT * FROM #tb_table;

SELECT *
FROM ##tb_table

执行上面的局部临时表和全局临时表创建语句之后,我们在SSMS中新开启一个连接,执行下面的语句:

SELECT *
FROM ##tb_table
GO

SELECT *
FROM #tb_table

返回执行结果如下:
01.png
返回执行消息如下:
02.png
从返回的结果分析可知:局部临时表仅当前连接可以访问,对其他进程不可见(访问报告对象不存在的错误),而全局临时表不仅当前连接可以访问,对其他进程可见。

写在最后

关于SQL Server表变量和临时表的使用规则是一个仁者见仁智者见智的话题,所以我们希望能够把这个话题尽可能的剖析清楚,让读者对两者有非常清楚的认识。

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
7天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
47 10
|
25天前
|
SQL Perl
PL/SQL编程基本概念
PL/SQL编程基本概念
13 0
|
1月前
|
SQL 数据库 数据安全/隐私保护
Sql Server数据库Sa密码如何修改
Sql Server数据库Sa密码如何修改
|
17天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
16 0
|
7天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
66 6
|
8天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
12天前
|
SQL 安全 Java
SQL server 2017安装教程
SQL server 2017安装教程
14 1
|
25天前
|
SQL 存储 Python
Microsoft SQL Server 编写汉字转拼音函数
Microsoft SQL Server 编写汉字转拼音函数
|
1月前
|
SQL 存储 数据库
数据安全无忧,SQL Server 2014数据库定时备份解密
数据安全无忧,SQL Server 2014数据库定时备份解密
|
1月前
|
SQL 网络协议 Windows
破解SQL Server迷局,彻底解决“管道的另一端无任何进程错误233”
破解SQL Server迷局,彻底解决“管道的另一端无任何进程错误233”