In the case of high concurrency and high load, how to add fields to the table and set the DEFAULT value?

 

In the case of high concurrency and high load, how to add fields to the table and set the DEFAULT value?

 

 

 

Before Oracle 12c, when the Oracle table had hundreds of millions of data, efficiency and security were the factors that must be considered when performing the "ALTER TABLE XXX ADD COLUMN_XX VARCHAR2(2) DEFAULT 'XXX';" operation on the table. If it is executed directly, a 6-level table lock will be added to the table during the process, that is, even the query needs to wait, which is a very dangerous operation on the production database. Because Oracle not only needs to update the data dictionary, but also refresh all the records during the above operation, and it will cause the Undo table space to skyrocket. Therefore, the correct way is to separate the update data dictionary and update field values.

For example, the table LKILL.T_KILL has about 4500W of data, and it takes 21 minutes to directly add a field C_LHR, as shown below:

12:20:17 SYS@RACLHR2> ALTER TABLE LKILL.T_KILL ADD C_LHR VARCHAR2(100) DEFAULT 'LHR';

Table altered.

Elapsed: 00:21:58.53

If it is modified as follows, the performance of this operation can be significantly improved, but the original record in the table is empty for the newly added column, and the default value of the newly added record will be set to LHR, then the default value of the original record needs to be in the When the system is idle, perform batch update, batch submission, or use the system package DBMS_PARALLEL_EXECUTE to update, so as not to lock the table in large quantities, please refer to the batch update part in this book [ REF _Ref24783 \n \h 3.1.10.5 REF _Ref24783 \h Batch insert, batch update, batch delete, batch submit]. As follows:

12:42:17 SYS@RACLHR2> ALTER TABLE LKILL.T_KILL ADD A_LHR VARCHAR2(100);

Table altered.

Elapsed: 00:00:00.35

13:53:54 SYS@RACLHR2> ALTER TABLE LKILL.T_KILL MODIFY A_LHR VARCHAR2(100) DEFAULT 'LHR';

Table altered.

Elapsed: 00:00:00.06

It should be noted that starting from Oracle 11g, when adding a non-null column with a default value (note the 2 conditions, NOT NULL and the default value), Oracle will not use this default value to physically update existing rows , Oracle will only store this new column metadata (NOT NULL constraint and DEFAULT default value), so that adding a non-null column with a default value to the table can be done in an instant. Of course, there is a partial NVL function cost when retrieving the column from the table. The specific nuances can be analyzed through the 10046 event, which will not be analyzed in detail here.

Starting from Oracle 12c, the DDL statement optimization of adding columns with empty columns with default values ​​is supported, that is, the efficiency of the following two SQL statements is the same, and there is no lock table phenomenon:

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

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

An example is shown below:

LHR@OCPLHR1> select * from v$version where rownum<=1;

 

BANNER

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

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

 

LHR@OCPLHR1> set time on

16:59:00 LHR@OCPLHR1> set timing on

16:59:08 LHR@OCPLHR1> 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 LHR@OCPLHR1> SELECT d.bytes FROM user_segments d WHERE d.segment_name='T1';

 

     BYTES

----------

   7340032

 

Elapsed: 00:00:00.09

17:01:00 LHR@OCPLHR1> ALTER TABLE t1 ADD c_ddl NUMBER DEFAULT 666 ;

 

Table altered.

 

Elapsed: 00:00:25.29

17:02:07 LHR@OCPLHR1> SELECT d.bytes FROM user_segments d WHERE d.segment_name='T1';

 

     BYTES

----------

   8388608

 

Elapsed: 00:00:00.01

17:02:13 LHR@OCPLHR1> ALTER TABLE t1 ADD c_ddl2 NUMBER DEFAULT 888 not null;

 

Table altered.

 

Elapsed: 00:00:00.08

17:02:37 LHR@OCPLHR1> SELECT d.bytes FROM user_segments d WHERE d.segment_name='T1';

 

     BYTES

----------

   8388608

 

Elapsed: 00:00:00.01

It can be seen that in Oracle 11g, the SQL statement with the NOT NULL constraint can complete the operation of adding columns in an instant, while the SQL statement with only the default value takes 25 seconds. In addition, after the SQL statement with the NOT NUL constraint is executed, the size of the table does not change, which also shows that Oracle has not done physical updates.

Check its execution plan below, be careful not to use the "SET AUTOT ON" method here, otherwise you cannot see its real execution plan:

17:05:30 LHR@OCPLHR1> SELECT COUNT(*) FROM t1 WHERE c_ddl2=888;

 

  COUNT(*)

----------

    200000

 

Elapsed: 00:00:00.02

17:05:39 LHR@OCPLHR1> 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 LHR@OCPLHR1> SELECT * FROM t1 WHERE rownum<=1;

 

        N1         N2         N3 CL              C_DDL     C_DDL2

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

         1 0 8 XYGGZXRRYR 666 888

As you can see, the NVL function appears in the predicate part. Therefore, Oracle considers the C_DDL2 column to be an empty column.

The following tests whether the index can be used:

17:29:24 LHR@OCPLHR1> CREATE INDEX idx_c_ddl2 ON t1(c_ddl2);

 

Index created.

 

Elapsed: 00:00:00.71

17:31:08 LHR@OCPLHR1> update t1 set c_ddl2='8881' where rownum<=1;

 

1 row updated.

 

Elapsed: 00:00:00.05

17:31:13 LHR@OCPLHR1> commit;

 

Commit complete.

 

Elapsed: 00:00:00.00

17:31:16 LHR@OCPLHR1> 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 LHR@OCPLHR1> 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

Surprisingly, indexes are used.

Let's take a look at the implementation in Oracle 12c:

 

LHR@lhr121> set line 120

LHR@lhr121> 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

LHR@lhr121> 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

LHR@lhr121> SELECT d.bytes FROM user_segments d WHERE d.segment_name='T1';

 

     BYTES

----------

   4194304

 

Elapsed: 00:00:00.33

LHR@lhr121>  ALTER TABLE t1 ADD c_ddl NUMBER DEFAULT 666 ;

 

Table altered.

 

Elapsed: 00:00:00.65

LHR@lhr121> SELECT d.bytes FROM user_segments d WHERE d.segment_name='T1';

 

     BYTES

----------

   4194304

 

Elapsed: 00:00:00.14

LHR@lhr121> ALTER TABLE t1 ADD c_ddl2 NUMBER DEFAULT 888 not null;

 

Table altered.

 

Elapsed: 00:00:00.15

LHR@lhr121> SELECT d.bytes FROM user_segments d WHERE d.segment_name='T1';

 

     BYTES

----------

   4194304

 

Elapsed: 00:00:00.09

 

LHR@lhr121> SELECT COUNT(*) FROM t1 WHERE c_ddl2=888;

 

  COUNT(*)

----------

    100000

 

Elapsed: 00:00:00.02

LHR@lhr121>  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

 

LHR@lhr121> SELECT COUNT(*) FROM t1 WHERE c_ddl=666;

 

  COUNT(*)

----------

    100000

 

Elapsed: 00:00:00.04

LHR@lhr121>  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

LHR@lhr121> 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

LHR@lhr121>

It is clear from the example that in Oracle 12c, adding DDL optimizations with default values ​​has been extended to include empty columns with default values. Oracle used an undocumented function SYS_OP_VECBIT and a new hidden column SYS_NC00005$ because the column was not physically updated.

& Description:

For more details about batch updates and the use of DBMS_PARALLEL_EXECUTE, please refer to my BLOG: ① http://blog.itpub.net/26736162/viewspace-2140626/ ②http://blog.itpub.net/26736162/viewspace-1684396

 

 

 

 

 

 

 

 

About Me

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

● The author of this article: Wheat Miao, some of the content is organized from the Internet, if there is any infringement, please contact Wheat Miao to delete

● This article is updated simultaneously on itpub ( http://blog.itpub.net/26736162/abstract/1/ ), blog garden ( http://www.cnblogs.com/lhrbest ) and personal WeChat public account ( xiaomaimiaolhr )

● The itpub address of this article: http://blog.itpub.net/26736162/abstract/1/

● The blog address of this article: http://www.cnblogs.com/lhrbest

● The pdf version of this article, personal profile and the address of the wheat seedling cloud disk: http://blog.itpub.net/26736162/viewspace-1624453/

● Database written test interview questions and answers: http://blog.itpub.net/26736162/viewspace-2134706/

● DBA Collection Today Toutiao address: http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826

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

● QQ group number: 230161599 (full) , 618766405

● WeChat group: you can add me on WeChat, I will pull everyone into the group, if you are the one

● Contact me, please add QQ friends ( 646634621 ) , and indicate the reason for adding

● Completed in Magic City from 2018-02-01 06:00 ~ 2018-02-31 24:00

● The content of the article comes from the study notes of Wheat Miao, and some of them are compiled from the Internet. If there is any infringement or inappropriateness, please forgive me

● All rights reserved, welcome to share this article, please keep the source for reprinting

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

Weidian of Wheat Miao : https://weidian.com/s/793741433?wfr=c&ifr=shopdetail

Database series books published by Wheat Miao : http://blog.itpub.net/26736162/viewspace-2142121/

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

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

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

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

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

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

 

DBA笔试面试讲解群 《DBA宝典》读者群 欢迎与我联系

 

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326307800&siteId=291194637