sql server 中怎么给表中增加一列?

sql server 中怎么给表中增加一列?,第1张

1、首先我们准备一个数据表,接下来将会在这个表中添加列

2、然后我们通过alter  table语句来给表添加一个列

3、回到数据表一会我们看到列已经被添加进数据表了,但是默认值却没有

4、接下来我们在添加列的时候同时添加上默认值,这个时候运用default关键字

5、然后回到数据表,我们就看到默认值有内容了

6、另外在数据表中经常使用的是uniqueidentifier类型,这种字段设置默认值需要按如下图所示的方式进行

7、回到数据表中我们可以看到默认值已经添加上了一列

传统情况

我们先回顾一下,在没有 "立刻加列" 功能时,加列 *** 作是怎么完成的。我们也借此来熟悉一下本期的图例:

当进行 加列 *** 作 时,所有的数据行 都必须要 增加一段数据(图中的 列 4 数据)

如上一期图解所讲,当改变数据行的长度,就需要 重建表空间(图中灰蓝的部分为发生变更的部分)

数据字典中的列定义也会被更新

以上 *** 作的问题在于 每次加列 *** 作都需要重建表空间,这就需要大量 IO以及大量的时间

立刻加列

"立刻加列" 的过程如下图:

请点击输入图片描述

请点击输入图片描述

"立刻加列" 时,只会变更数据字典中的内容,包括:

在列定义中增加 新列的定义

增加 新列的默认值

"立刻加列" 后,当要读取表中的数据时:

由于 "立刻加列" 没有 变更行数据,读取的行数据只有 3 列

MySQL 会将 新增的第 4 列的默认值,追加到 读取的数据后

以上过程描述了 如何读取 在 "立刻加列" 之前写入的数据,其实质是:在读取数据的过程中,"伪造" 了一个新列出来

那么如何读取 在 "立刻加列" 之后 写入的数据呢 ? 过程如下图:

当读取 行 4 时:

请点击输入图片描述

请点击输入图片描述

通过判断 数据行的头信息中的instant 标志位,可以知道该行的格式是 "新格式":该行头信息后有一个新字段 "列数"

通过读取 数据行的 "列数" 字段,可以知道 该行数据中多少列有 "真实" 的数据,从而按列数读取数据

通过上图可以看到:读取 在"立刻加列" 前/后写入的数据是不同的流程

通过以上的讨论,我们可以总结 "立刻加列" 之所以高效的原因是:

在执行 "立刻加列" 时,不变更数据行的结构

读取 "旧" 数据时,"伪造" 新增的列,使结果正确

写入 "新" 数据时,使用了新的数据格式(增加了instant标志位 和 "列数" 字段),以区分新旧数据

读取 "新" 数据时,可以如实读取数据

那么 我们是否能一直 "伪造" 下去 ? "伪造" 何时会被拆穿 ?

考虑以下场景:

用 "立刻加列" 增加列 A

写入数据行 1

用 "立刻加列" 增加列 B

写入数据行 2

删除列 B

我们推测一下 "删除列 B" 的最小代价:需要修改 数据行中的instant标志位或 "列数" 字段,这至少会影响到 "立刻加列" 之后写入的数据行,成本类似于重建数据

从以上推测可知:当出现 与 "立刻加列"  *** 作不兼容 的 DDL *** 作时,数据表需要进行重建,如下图所示:

请点击输入图片描述

请点击输入图片描述

扩展思考题:是否能设计其他的数据格式,取代instant标志位和 "列数" 字段,使得 加列/删列 *** 作都能 "立刻完成" ?(提示:考虑 加列 - 删列 - 再加列 的情况)

使用限制

在了解原理之后,我们来看看 "立刻加列" 的使用限制,就很容易能理解其中的前两项:

"立刻加列" 的加列位置只能在表的最后,而不能加在其他列之间

在元数据中,只记录了 数据行 应有多少列,而没有记录 这些列 应出现的位置。所以无法实现指定列的位置

"立刻加列" 不能添加主键列

加列 不能涉及聚簇索引的变更,否则就变成了 "重建" *** 作,不是 "立刻" 完成了

"立刻加列"不支持压缩的表格式

按照 WL 的说法:"COMPRESSED is no need to supported"(没必要支持不怎么用的格式)

总结回顾

我们总结一下上面的讨论:

"立刻加列" 之所以高效的原因是:

在执行 "立刻加列" 时,不变更数据行的结构

读取 "旧" 数据时,"伪造" 新增的列,使结果正确

写入 "新" 数据时,使用了新的数据格式 (增加了 instant 标志位 和 "列数" 字段),以区分新旧数据

读取 "新" 数据时,可以如实读取数据

"立刻加列" 的 "伪造" 手法,不能一直维持下去。当发生 与 "立刻加列" *** 作不兼容 的 DDL 时,表数据就会发生重建

回到之前遗留的两个问题:

"立刻加列" 是如何工作的 ?

我们已经解答了这个问题

所谓 "立刻加列" 是否完全不影响业务,是否是真正的 "立刻" 完成 ?

可以看到:就算是 "立刻加列",也需要变更 数据字典,那么 该上的锁还是逃不掉的。也就是说 这里的 "立刻" 指的是 "不变更数据行的结构",而并非指 "零成本地完成任务"

在数据量变的很大的情况下,可以考虑表压缩,减少磁盘的存储,减少buffer cache的消耗,加快查询的速度,压缩需要在数据加载和dml的时候消耗一些cpu.表压缩对于应用是透明的。

你可以在表空间,表或分区级别指定压缩,如果在表空间级别指定压缩,那么这个表空间中的所有表默认都是压缩的。

压缩会发生在数据插入,更新或批量加载到表时。有几种类型的压缩。基本的,oltp的,dss的,归档的。他们的cpu消耗见文档。

当使用基本压缩,数据仓库压缩,或归档压缩的时候,压缩仅仅是在批量加载到一个表的时候发生。当你使用了oltp压缩,压缩发生在数据插入,更新,批量加载。

如果你使用了alter table命令让表启用压缩,那么对于已存在的数据是不受影响的,只有在启用压缩后的插入,或更新会受影响。也可以使用ALTER TABLE…NOCOMPRESS将一个表设置成非压缩,对于已经的压缩的表是没有影响的,压缩的数据还是压缩的,只是新插入的数据是不被压缩。

创建一个oltp压缩类型的表

CREATE TABLE orders  …  COMPRESS FOR OLTP

如果你不指定压缩的类型,那么默认的情况下是基本压缩类型。下面的2个语句是等价的。

CREATE TABLE sales_history  …  COMPRESS BASIC

CREATE TABLE sales_history  …  COMPRESS

下面的表是一个数据仓库压缩类型的表,对于经常查询,并且没有dml的表适用。

CREATE TABLE sales_history  …  COMPRESS FOR QUERY

创建一个归档压缩类型的表

CREATE TABLE sales_history  …  COMPRESS FOR ARCHIVE

表可以包含压缩和非压缩的分区,并且不同的分区的压缩的类型可以是不同的,如果在分区上指定的压缩的类型与表上指定的压缩的类型不同,那么分区上的优先。

查看表是否是压缩的,及分区是否是压缩的。

SQL>SELECT table_name, compression, compress_for FROM user_tables

SELECT table_name, partition_name, compression,compress_for

FROM user_tab_partitions

查看表中的行是什么压缩类型

SELECT DECODE(DBMS_COMPRESSION.GET_COMPRESSION_TYPE(

ownname =>‘HR’,

tabname =>‘EMPLOYEES’,

row_id  =>‘AAAVEIAAGAAAABTAAD’),

1,  ‘No Compression’,

2,  ‘Basic or OLTP Compression’,

4,  ‘Hybrid Columnar Compression for Query High’,

8,  ‘Hybrid Columnar Compression for Query Low’,

16, ‘Hybrid Columnar Compression for Archive High’,

32, ‘Hybrid Columnar Compression for Archive Low’,

‘Unknown Compression Type’) compression_type

FROM DUAL

修改压缩的级别

如果表是分区表,使用在线重定义可以修改表的压缩级别。如果表是分分区表,那么可以使用alter table ..move.. compress for语句修改表的压缩级别,这个语句会阻塞dml *** 作。

对于压缩表的限制:

1基本压缩,你不能为添加的列指定默认的值。删除列是不被支持的。

2oltp压缩,如果要添加一个带默认值的列,那么需要指定not null,可以删除列,但是数据只是在内部做了一个不被使用的标记而已。

3在线段收缩是不被支持的。

4上面的压缩的方式不适合于lobs类型,他们有自己的压缩方式。

5基本压缩类型的表的pct_free参数自动的设置成0.

在上面的描述中可以看到对于基本类型的压缩,没有使用直接路径插入的行及更新的行是不会被压缩的。对于我们的oltp系统基本是没有用处的,只测试下oltp的压缩方式,这种方式对于没有使用直接路径插入的行及被更新的行都会压缩。

SQL>select count(*) from baixyu2

COUNT(*)

22096384

SQL>set serveroutput on

SQL> exec show_space(‘BAIXYU2’,’T’,’AUTO’)

Total Blocks……………………….334336

Total Bytes………………………..2738880512

Unused Blocks………………………1916

Unused Bytes……………………….15695872

Last Used Ext FileId………………..4

Last Used Ext BlockId……………….671872

Last Used Block…………………….6276

CREATE TABLE baixyu3  COMPRESS FOR OLTP as select * from baixyu2

SQL> exec show_space(‘BAIXYU3’,’T’,’AUTO’)

Total Blocks……………………….107520

Total Bytes………………………..880803840

Unused Blocks………………………112

Unused Bytes……………………….917504

Last Used Ext FileId………………..4

Last Used Ext BlockId……………….116224

Last Used Block…………………….912

看到使用的块由33w下降到10w。压缩效果还是不错,但是是否使用还要结果上面的限制来根据实际情况评估。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/8019672.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-12
下一篇2023-04-12

发表评论

登录后才能评论

评论列表(0条)

    保存