在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?

在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?




在Oracle 12c之前,当Oracle表数据量上亿时,对表执行“ALTER TABLE XXX ADD COLUMN_XX
VARCHAR2(2) DEFAULT ‘XXX‘;”操作时,效率及安全性是必须要考虑的因素。若直接执行,则会在该过程中给表加上6级表锁,也就是连查询都需要等待,这在生产库上是相当危险的操作。因为Oracle在执行上述操作过程中,不仅要更新数据字典,还会刷新全部的记录,并且会使得Undo表空间暴涨,所以,正确的做法是将更新数据字典和更新字段值分开。

例如,表LKILL.T_KILL约有4500W的数据,直接添加一个字段C_LHR需要花费21分钟,如下所示:

12:20:17 [email protected]> ALTER TABLE LKILL.T_KILL ADD
C_LHR VARCHAR2(100) DEFAULT ‘LHR‘;

Table altered.

Elapsed:
00:21:58.53

若修改为如下的方式,则可以显著提高这个操作的性能,但表中原有的记录对于新添加的列为空,新增记录默认值会设置为LHR,那么原有记录的默认值就需要在系统空闲的时候进行批量更新、批量提交或采用系统包DBMS_PARALLEL_EXECUTE来更新,这样不至于大批量锁表,请参考本书中分批更新的部分【 REF _Ref24783 \n \h 3.1.10.5 REF _Ref24783 \h 分批插入、分批更新、分批删除、分批提交】。如下所示:

12:42:17 [email protected]> ALTER TABLE LKILL.T_KILL ADD
A_LHR VARCHAR2(100);

Table altered.

Elapsed:
00:00:00.35

13:53:54 [email protected]> ALTER TABLE LKILL.T_KILL
MODIFY A_LHR VARCHAR2(100) DEFAULT ‘LHR‘;

Table altered.

Elapsed:
00:00:00.06

需要注意的是,从Oracle 11g开始,当添加一个带有默认值的非空列时(注意2个条件,NOT NULL和默认值),Oracle不会使用这个默认值来物理更新现有存在的行,Oracle只会存储这个新列元数据(NOT NULL约束和DEFAULT默认值),从而使得对该表的添加带有默认值的非空列操作可以在瞬间完成。当然,从表中检索该列时,会有部分的NVL函数代价。具体的细微差别可以通过10046事件来分析,这里不再详细解析。

从Oracle 12c开始,支持具有默认值的空列的添加列的DDL语句优化,即如下2条SQL语句的效率是一样的,也不存在锁表的现象了:

ALTER TABLE LKILL.T_KILL ADD A_LHR VARCHAR2(100);

ALTER TABLE LKILL.T_KILL ADD A_LHR VARCHAR2(100)
NOT NULL;

示例如下所示:

[email protected]> select * from v$version where
rownum<=1;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0
- 64bit Production

[email protected]> set time on

16:59:00 [email protected]> set timing on

16:59:08 [email protected]> CREATE TABLE t1 AS

16:59:21  
2  SELECT ROWNUM N1,

16:59:21  
3         TRUNC((ROWNUM - 1) / 3)
N2,

16:59:21  
4         TRUNC(DBMS_RANDOM.VALUE(ROWNUM,
ROWNUM * 10)) N3,

16:59:21  
5         DBMS_RANDOM.STRING(‘U‘,
10) cl

16:59:21  
6    FROM DUAL

16:59:21  
7  CONNECT BY LEVEL <= 200000;

Table created.

Elapsed: 00:00:05.72

16:59:45 [email protected]> SELECT d.bytes FROM
user_segments d WHERE d.segment_name=‘T1‘;

BYTES

----------

7340032

Elapsed: 00:00:00.09

17:01:00 [email protected]> ALTER TABLE
t1 ADD c_ddl NUMBER DEFAULT 666 ;

Table altered.

Elapsed:
00:00:25.29

17:02:07 [email protected]> SELECT d.bytes FROM
user_segments d WHERE d.segment_name=‘T1‘;

BYTES

----------

8388608

Elapsed: 00:00:00.01

17:02:13 [email protected]> ALTER TABLE
t1 ADD c_ddl2 NUMBER DEFAULT 888 not null;

Table altered.

Elapsed:
00:00:00.08

17:02:37 [email protected]> SELECT d.bytes FROM
user_segments d WHERE d.segment_name=‘T1‘;

BYTES

----------

8388608

Elapsed: 00:00:00.01

可以看出,在Oracle 11g中,加了NOT
NULL约束的SQL语句,可以在瞬间完成添加列的操作,而只设置了默认值的SQL语句使用了25秒的时间。另外,加了NOT NUL约束的SQL语句执行完毕后,表的大小没有变化,这也说明了Oracle并没有做物理更新。

下面查看其执行计划,注意在这里不要使用“SET AUTOT ON”的方式,否则不能看到其真实的执行计划:

17:05:30 [email protected]> SELECT COUNT(*) FROM t1
WHERE c_ddl2=888;

COUNT(*)

----------

200000

Elapsed: 00:00:00.02

17:05:39 [email protected]> select  * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------

SQL_ID 
bq50v8z914juk, child number 0

-------------------------------------

SELECT COUNT(*) FROM t1 WHERE c_ddl2=888

Plan hash value: 3724264953

---------------------------------------------------------------------------

|
Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |     
|       |       |  
282 (100)|          |

|   1 | 
SORT AGGREGATE    |      |    
1 |    13 |            |          |

|*  2 |  
TABLE ACCESS FULL| T1   |   199K| 
2530K|   282   (2)| 00:00:04 |

---------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter(NVL("C_DDL2",888)=888)

Note

-----

- dynamic
sampling used for this statement (level=2)

23 rows selected.

17:08:55 [email protected]> SELECT * FROM t1 WHERE
rownum<=1;

N1         N2         N3 CL              C_DDL     C_DDL2

----------
---------- ---------- ---------- ---------- ----------

1          0          8 XYGGZXRRYR        666        888

可以看到,在谓词部分出现了NVL函数。所以,Oracle认为C_DDL2列是空列。

下面测试是否可以使用索引:

17:29:24 [email protected]> CREATE INDEX idx_c_ddl2 ON
t1(c_ddl2);

Index created.

Elapsed: 00:00:00.71

17:31:08 [email protected]> update t1 set
c_ddl2=‘8881‘ where rownum<=1;

1 row updated.

Elapsed: 00:00:00.05

17:31:13 [email protected]> commit;

Commit complete.

Elapsed: 00:00:00.00

17:31:16 [email protected]> SELECT * FROM t1 WHERE
c_ddl2=8881;

N1         N2         N3 CL              C_DDL     C_DDL2

---------- ---------- ---------- ----------
---------- ----------

1          0          8 XYGGZXRRYR        666       8881

Elapsed: 00:00:00.01

17:31:24 [email protected]> select  * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

SQL_ID 
0sm5s7zkvycrq, child number 0

-------------------------------------

SELECT * FROM t1 WHERE c_ddl2=8881

Plan hash value: 1464185165

------------------------------------------------------------------------------------------

| Id  |
Operation                   | Name       | Rows 
| Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------

|   0 |
SELECT STATEMENT            |            |       |      
|     2 (100)|          |

|   1 |  TABLE ACCESS BY INDEX ROWID| T1         |    
1 |    34 |     2  
(0)| 00:00:01 |

|*  2 |  
INDEX RANGE SCAN          |
IDX_C_DDL2 |     1 |       |    
1   (0)| 00:00:01 |

------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 -
access("C_DDL2"=8881)

19 rows selected.

Elapsed: 00:00:00.11

令人惊喜的是,使用了索引。

下面看看在Oracle 12c中的执行情况:

[email protected]> set line 120

[email protected]> select * from v$version where
rownum<=1;

BANNER                                                                              
CON_ID

--------------------------------------------------------------------------------
----------

Oracle Database 12c Enterprise Edition Release
12.1.0.2.0 - 64bit Production             
0

Elapsed: 00:00:00.00

[email protected]> CREATE TABLE t1 AS

2  SELECT ROWNUM N1,

3         TRUNC((ROWNUM - 1) / 3) N2,

4         TRUNC(DBMS_RANDOM.VALUE(ROWNUM, ROWNUM
* 10)) N3,

DBMS_RANDOM.STRING(‘U‘, 10) cl

6    FROM DUAL

7  CONNECT BY LEVEL <= 100000;

Table created.

Elapsed: 00:00:09.41

[email protected]> SELECT d.bytes FROM user_segments d
WHERE d.segment_name=‘T1‘;

BYTES

----------

4194304

Elapsed: 00:00:00.33

[email protected]>  ALTER TABLE t1
ADD c_ddl NUMBER DEFAULT 666 ;

Table altered.

Elapsed: 00:00:00.65

[email protected]> SELECT d.bytes FROM user_segments d
WHERE d.segment_name=‘T1‘;

BYTES

----------

4194304

Elapsed: 00:00:00.14

[email protected]> ALTER TABLE t1 ADD c_ddl2 NUMBER DEFAULT 888 not
null;

Table altered.

Elapsed: 00:00:00.15

[email protected]> SELECT d.bytes FROM user_segments d
WHERE d.segment_name=‘T1‘;

BYTES

----------

4194304

Elapsed: 00:00:00.09

[email protected]> SELECT COUNT(*) FROM t1 WHERE
c_ddl2=888;

COUNT(*)

----------

100000

Elapsed: 00:00:00.02

[email protected]> 
select  * from
table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

-----------------------------------------------------------------------------

SQL_ID 
bq50v8z914juk, child number 1

-------------------------------------

SELECT COUNT(*) FROM t1 WHERE c_ddl2=888

Plan hash value: 3724264953

---------------------------------------------------------------------------

| Id  |
Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------

|   0 |
SELECT STATEMENT   |      |      
|       |   122 (100)|          |

|   1 |  SORT AGGREGATE    |     
|     1 |    13 |            |          |

|*  2 |   TABLE ACCESS FULL| T1   |  
100K|  1269K|   122  
(1)| 00:00:01 |

---------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 -
filter(NVL("C_DDL2",888)=888)

Note

-----

-
statistics feedback used for this statement

23 rows selected.

Elapsed: 00:00:00.05

[email protected]> SELECT COUNT(*) FROM t1 WHERE
c_ddl=666;

COUNT(*)

----------

100000

Elapsed: 00:00:00.04

[email protected]> 
select  * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

------------------------------------------------------------------------------------------------------------------------

SQL_ID 
dph2gfp6f0jja, child number 1

-------------------------------------

SELECT COUNT(*) FROM t1 WHERE c_ddl=666

Plan hash value: 3724264953

---------------------------------------------------------------------------

| Id  |
Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |

---------------------------------------------------------------------------

|   0 |
SELECT STATEMENT   |      |      
|       |   122 (100)|          |

|   1 |  SORT AGGREGATE    |     
|     1 |    13 |            |          |

|*  2 |   TABLE ACCESS FULL| T1   | 
1000 | 13000 |   122   (1)| 00:00:01 |

---------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

2 -
filter(DECODE(TO_CHAR(SYS_OP_VECBIT("SYS_NC00005$",0)),NULL,NVL("

C_DDL",666),‘0‘,NVL("C_DDL",666),‘1‘,"C_DDL")=666)

20 rows selected.

Elapsed: 00:00:00.12

[email protected]> SELECT d.column_name,
d.column_id,d.hidden_column,d.virtual_column FROM Dba_Tab_Cols d  WHERE d.table_name=‘T1‘ order by column_id;

COLUMN_NAME      COLUMN_ID HID VIR

---------------
---------- --- ---

N1                       1 NO  NO

N2                       2 NO  NO

N3                       3 NO  NO

CL                       4 NO  NO

C_DDL                    5 NO  NO

C_DDL2                   6 NO  NO

SYS_NC00005$               YES NO

7 rows selected.

Elapsed: 00:00:00.32

[email protected]>

从示例可以清楚地看到,在Oracle 12c中,添加具有默认值的DDL优化已扩展到包括默认值的空列。Oracle使用了一个未公开的函数SYS_OP_VECBIT和新的隐藏列SYS_NC00005$,因为该列没有被物理更新。

&说明:

有关批量更新和DBMS_PARALLEL_EXECUTE的使用更详细的内容可以参考我的BLOG:①
http://blog.itpub.net/26736162/viewspace-2140626/
②http://blog.itpub.net/26736162/viewspace-1684396





About Me


.............................................................................................................................................

● 本文作者:小麦苗,部分内容整理自网络,若有侵权请联系小麦苗删除

● 本文在itpub(http://blog.itpub.net/26736162/abstract/1/)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新

● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/

● 本文博客园地址:http://www.cnblogs.com/lhrbest

● 本文pdf版、个人简介及小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/

● 数据库笔试面试题库及解答:http://blog.itpub.net/26736162/viewspace-2134706/

● DBA宝典今日头条号地址:http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826

.............................................................................................................................................

● QQ群号:230161599(满)、618766405

● 微信群:可加我微信,我拉大家进群,非诚勿扰

● 联系我请加QQ好友(646634621),注明添加缘由

● 于 2018-02-01 06:00 ~ 2018-02-31 24:00 在魔都完成

● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解

● 版权所有,欢迎分享本文,转载请保留出处

.............................................................................................................................................

● 小麦苗的微店:https://weidian.com/s/793741433?wfr=c&ifr=shopdetail

● 小麦苗出版的数据库类丛书:http://blog.itpub.net/26736162/viewspace-2142121/

● 好消息:小麦苗OCP、OCM开班啦,详情请点击:http://blog.itpub.net/26736162/viewspace-2148098/

.............................................................................................................................................

使用微信客户端扫描下面的二维码来关注小麦苗的微信公众号(xiaomaimiaolhr)及QQ群(DBA宝典),学习最实用的数据库技术。

小麦苗的微信公众号      小麦苗的DBA宝典QQ群2     《DBA笔试面试宝典》读者群       小麦苗的微店

.............................................................................................................................................

原文地址:https://www.cnblogs.com/lhrbest/p/8439345.html

时间: 2024-11-02 10:57:54

在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?的相关文章

mysql主主+keepalived高并发高负载情况测试数据一致性问题

我们对mysql双主+keepalived高可用做了一下测试, mysql做了gtid多线程复制,也做了优化,最后我们的目的是看看,这种高可用在高并发高负载的情况下,down机一台,最后看看两者之间的数据是否一致性,经过几次测试, 我们让开发写了一小段程序,持续往数据库中写数据, 我们找了大概6,7台客户端,同时去想数据库写数据,每个客户端30个线程, 然后在将一台mysql关机,看最后的效果, 其中一台关机,另一台持续写数据,down机的一台在数据写完之前启动起来,而且这台机器上面keepal

java处理高并发高负载类网站的优化方法

一:高并发高负载类网站关注点之数据库 没错,首先是数据库,这是大多数应用所面临的首个SPOF.尤其是Web2.0的应用,数据库的响应是首先要解决的. 一般来说MySQL是最常用的,可能最初是一个mysql主机,当数据增加到100万以上,那么,MySQL的效能急剧下降.常用的优化措施是M-S(主-从)方式进行同步复制,将查询和操作和分别在不同的服务器上进行操作.我推荐的是M-M-Slaves方式,2个主Mysql,多个Slaves,需要注意的是,虽然有2个Master,但是同时只有1个是Activ

构建高并发高可用的电商平台架构实践(下)

构建高并发高可用的电商平台架构实践(下) 6. 数据存储 数据库存储大体分为以下几类,有关系型(事务型)的数据库,以oracle.mysql为代表,有keyvalue数据库,以redis和memcached db为代表,有文档型数据库如mongodb,有列式分布式数据库以HBase,cassandra,dynamo为代表,还有其他的图形数据库.对象数据 库.xml数据库等.每种类型的数据库应用的业务领域是不一样的,下面从内存型.关系型.分布式三个维度针对相关的产品做性能可用性等方面的考量分析.

PHP高并发高负载系统架构

1.为什么要进行高并发和高负载的研究 1.1.产品发展的需要 1.2.公司发展的需要 1.3.当前形式决定的 2.高并发和高负载的约束条件 2.1.硬件 2.2.部署 2.3.操作系统 2.4.Web 服务器 2.5.PHP 2.6.MySQL 2.7.测试 3.解决之道——硬件篇 处理能力的提升:部署多颗CPU,选择多核心.具备更高运算频率.更大高速缓存的CPU: 处理能力的提升最直接的反应在于Web请求的处理效率和PHP程序的执行效率. 内存带宽与容量:更大的内存带宽和容量: 内存带宽与容量

大型高并发高负载网站的系统架构剖析

发布:vashon 来自:BudiChina.com 更新:2015-05-20 摘要:一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了.随着互联网业务的不断丰富,网站相关的技术经过这些年的发展,已经细分到很细的方方面面,尤其对于大型网站来说,所采用的技术更是涉及面非常广,从硬件到软件.编程语言.数据库.WebServer.防火墙等各个领域都有了很高的要求,已经不是原来简单的html静态网站所能比拟的. 前言 鄙人先后在CERNET做过拨号接入,在Yahoo&3721搞过搜

由 12306.cn 谈谈高并发+高负载网站性能技术

12306.cn 网站挂了,被全国人民骂了.我这两天也在思考这个事,我想以这个事来粗略地和大家讨论一下网站性能的问题.因为仓促,而且完全基于本人有限的经验和了解, 所以,如果有什么问题还请大家一起讨论和指正.(这又是一篇长文,只讨论性能问题,不讨论那些用户界面.用户体验.或是是否把支付和购票下单环节分开的功 能性的东西) 甲.认识业务的特殊性 任何技术都离不开业务需求,所以,要说明性能问题,首先还是想先说说业务问题. 其一,有人可能把这个东西和扣扣或是网游相比.但我觉得这两者是不一样的,网游和扣

高并发高负载的大型站点系统架构

大型站点的系统架构须要考虑非常多问题.大型站点有高并发高负载的特点,在面对大量用户訪问.高并发请求方面.主要的解决方式集中在这样几个环节:使用高性能的server.高性能的数据库.高效率的编程语言.还有高性能的Web容器.本文从低成本.高性能和高扩张性的角度来探讨了一些大型站点系统架构须要考虑的问题. AD:WOT2014:用户标签系统与用户数据化运营培训专场 一个小型的站点.比方个人站点,能够使用最简单的html静态页面就实现了.配合一些图片达到美化效果,全部的页面均存放在一个文件夹下,这种站

高并发高负载的大型网站系统架构(转)

高并发高负载的大型网站系统架构(转) 一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统架构.性能的要求都很简单,随着互联网业务的不断丰富,网站相关的技术经过这些年的发展,已经细分到很细的方方面面,尤其对于大型网站来说,所采用的技术更是涉及面非常广,从硬件到软件.编程语言.数据库.WebServer.防火墙等各个领域都有了很高的要求,已经不是原来简单的html静态网站所能比拟的. 大型网站,比如门户网站

高并发高负载的大型网站系统架构

大型网站的系统架构需要考虑很多问题.大型网站有高并发高负载的特点,在面对大量用户访问.高并发请求方面,基本的解决方案集中在这样几个环节:使用高性能的服务器.高性能的数据库.高效率的编程语言.还有高性能的Web容器.本文从低成本.高性能和高扩张性的角度来探讨了一些大型网站系统架构需要考虑的问题. AD:WOT2014:用户标签系统与用户数据化运营培训专场 一个小型的网站,比如个人网站,可以使用最简单的html静态页面就实现了,配合一些图片达到美化效果,所有的页面均存放在一个目录下,这样的网站对系统