Вы находитесь на странице: 1из 81

<Insert Picture Here>

Top 10, no make that 11, things about Oracle Database 11g Release 1
Thomas Kyte http://asktom.oracle.com

The Beginning...
Data Model with Structure Data Independent of Code Set-oriented 1977 the work begins

First RDBMS: Version 2 June 1979


FIRST Commercial SQL RDBMS Impressive First SQL
Joins, Subqueries Outer Joins, Connect By

A Simple Server
No transactions, Limited Reliability

Portability from the Start


Written in Fortran But multi-platform PDP11, Dec VAX

Oracle7.3 February 1996


Partitioned Views Bitmapped Indexes Asynchronous read ahead for table scans Standby Database Deferred transaction recovery on instance startup Updatable Join View SQLDBA no longer shipped. Index rebuilds DBV introduced Context Option PL/SQL - UTL_FILE

Spatial Data Option Tablespaces changes - Coalesce, Temporary Permanent, Trigger compilation, debug Unlimited extents on STORAGE clause. Some init.ora parameters modifiable - TIMED_STATISTICS HASH Joins, Antijoins Histograms Oracle Trace Advanced Replication Object Groups

Oracle Database Innovation


30 years of sustained innovation
Audit Vault Database Vault
Grid Computing Self Managing Database
XML Database Oracle Data Guard Real Application Clusters Flashback Query Virtual Private Database

Built in Java VM Partitioning Support Built in Messaging Object Relational Support Multimedia Support
Data Warehousing Optimizations Parallel Operations Distributed SQL & Transaction Support Cluster and MPP Support Multi-version Read Consistency Client/Server Support Platform Portability Commercial SQL Implementation

continuing with Oracle Database 11g


2007

1977

#1 Encrypted Tablespaces

Encrypted Tablespaces
Oracle Database 10g Release 2 introduced column encryption
Could not range scan Primary/foreign key issues

Tablespace encryption Removes those limitations Many encryption algorithms


3DES168 AES128 AES192 AES256

Encrypted Tablespaces
ops$tkyte%ORA11GR1> create tablespace encrypted 2 datafile '//encrypted.dbf' size 10m

ENCRYPTION default storage( encrypt );

Tablespace created. ops$tkyte%ORA11GR1> create tablespace clear 2 datafile '//clear.dbf' size 10m; Tablespace created.

Encrypted Tablespaces
ops$tkyte%ORA11GR1> create table t 2 tablespace clear

3
4

as
select * from all_users;

Table created. ops$tkyte%ORA11GR1> create index t_idx 2 3 on t(lower(username)) tablespace clear;

Index created.

Encrypted Tablespaces
ops$tkyte%ORA11GR1> alter system checkpoint; System altered. $ strings //clear.dbf | grep -i ops.tkyte OPS$TKYTE ops$tkyte from the table from the index

Encrypted Tablespaces
ops$tkyte%ORA11GR1> alter table t move 2 tablespace encrypted;

Table altered.
ops$tkyte%ORA11GR1> alter index t_idx rebuild 2 tablespace encrypted; Index altered.

Encrypted Tablespaces
ops$tkyte%ORA11GR1> alter system checkpoint; System altered. $ strings //encrypted.dbf | grep -i ops.tkyte [This space intentionally left blank]

Encrypted Tablespaces
ps$tkyte%ORA11GR1> set autotrace traceonly explain ops$tkyte%ORA11GR1> select * from t where lower(username) like 'ops$%'; Execution Plan ------------------------------------------------------------| Id | | Operation 0 | SELECT STATEMENT | Name | | Rows | | Bytes | 2 | 112 | -------------------------------------------------------------

|
|*

1 |
2 |

TABLE ACCESS BY INDEX ROWID| T


INDEX RANGE SCAN

2 |
1 |

112 |
|

| T_IDX |

------------------------------------------------------------Predicate Information (identified by operation id):

--------------------------------------------------2 - access(LOWER("USERNAME") LIKE 'ops$%') filter(LOWER("USERNAME") LIKE 'ops$%')

#2 Cache More Stuff

Cache More Everyone knows the fastest way to do something is to not do it


Client Side Cache Server Results Cache (JIT-MV) PL/SQL Function results cache Lots more detail in afternoon session

Cache More
ops$tkyte%ORA11GR1> /* ops$tkyte%ORA11GR1> drop table t;

ops$tkyte%ORA11GR1> create table t as select * from all_objects;


ops$tkyte%ORA11GR1> */ ops$tkyte%ORA11GR1> update t set object_type=object_type where rownum=1;

1 row updated.

Cache More
ops$tkyte%ORA11GR1> set autotrace traceonly ops$tkyte%ORA11GR1> select /*+ result_cache */

2
3 4 5 6 7 8

owner,
object_type, count(*) cnt from t group by owner, object_type order by owner, object_type /

249 rows selected.

Cache More
Execution Plan -------------------------------------------------------------------------------------------------| Id | | | | | Operation 0 | SELECT STATEMENT 1 | 2 | 3 | RESULT CACHE SORT GROUP BY | Name | | | Rows | Bytes | Cost (%CPU)| Time 1606K| | 1606K| 1606K| 284 280 284 | -------------------------------------------------------------------------------------------------| 58742 | | | 58742 | | 58742 | (2)| 00:00:04 | | | (2)| 00:00:04 | (1)| 00:00:04 | | 5cwffcum1ajfud1088m1m73f81 |

TABLE ACCESS FULL| T

-------------------------------------------------------------------------------------------------Result Cache Information (identified by operation id):

-----------------------------------------------------1 - column-count=3; dependencies=(OPS$TKYTE.T); parameters=(nls); name="select /*+ result_cache */ owner, object_type, count(*) cnt from t group by owner, object_type

order by"

Cache More
Statistics ---------------------------------------------------------0 0 1005 0 0 recursive calls db block gets consistent gets physical reads redo size

6922
596 18 1

bytes sent via SQL*Net to client


bytes received via SQL*Net from client SQL*Net roundtrips to/from client sorts (memory)

0
249

sorts (disk)
rows processed

Cache More
ops$tkyte%ORA11GR1> /
249 rows selected. Statistics ---------------------------------------------------------0 0 0 0 0 recursive calls db block gets consistent gets physical reads redo size

6922
596 18 0

bytes sent via SQL*Net to client


bytes received via SQL*Net from client SQL*Net roundtrips to/from client sorts (memory)

0
249

sorts (disk)
rows processed

Cache More
ops$tkyte%ORA11GR1> select * from ( 2 select /*+ result_cache */

3
4 5 6 7 8 9

owner, object_type, count(*) cnt


from t group by owner, object_type order by owner, object_type ) where cnt > 100 /

38 rows selected.

Cache More
Statistics ---------------------------------------------------------0 0 0 0 0 recursive calls db block gets consistent gets physical reads redo size

1516
442 4 0

bytes sent via SQL*Net to client


bytes received via SQL*Net from client SQL*Net roundtrips to/from client sorts (memory)

0
38

sorts (disk)
rows processed

Cache More
SQL> create or replace 2 3 4 function not_cached ( p_owner in varchar2 ) return number SQL> create or replace 2 3 4 5 6 5 6 7 8 9 10 11 12 13 begin select count(*) into l_cnt from t where owner = p_owner; dbms_lock.sleep(1); return l_cnt; as l_cnt number; 7 8 9 10 11 12 13 14 15 begin select count(*) into l_cnt from t where owner = p_owner; dbms_lock.sleep(1); return l_cnt; function cached ( p_owner in varchar2 ) return number result_cache relies_on(T) as l_cnt number;

14
15

end;
/

16
17

end;
/

Function created.

Function created.

Cache More
SQL> exec dbms_output.put_line( not_cached( 'SCOTT' ) ); 6 PL/SQL procedure successfully completed. Elapsed: 00:00:01.93 SQL> exec dbms_output.put_line( not_cached( 'SCOTT' ) ); 6

PL/SQL procedure successfully completed.


Elapsed: 00:00:01.29 SQL> exec dbms_output.put_line( not_cached( 'SCOTT' ) );

6
PL/SQL procedure successfully completed. Elapsed: 00:00:01.07

Cache More
SQL> exec dbms_output.put_line( cached( 'SCOTT' ) ); 6 PL/SQL procedure successfully completed. Elapsed: 00:00:01.09 SQL> exec dbms_output.put_line( cached( 'SCOTT' ) ); 6

PL/SQL procedure successfully completed.


Elapsed: 00:00:00.01 SQL> exec dbms_output.put_line( cached( 'SCOTT' ) );

6
PL/SQL procedure successfully completed. Elapsed: 00:00:00.01

Cache More
SQL> update t set owner = initcap(owner) where rownum = 1; 1 row updated.

SQL> commit;
Commit complete. SQL> exec dbms_output.put_line( cached( 'SCOTT' ) ); 6

PL/SQL procedure successfully completed.


Elapsed: 00:00:01.25 SQL> exec dbms_output.put_line( cached( 'SCOTT' ) ); 6

PL/SQL procedure successfully completed.


Elapsed: 00:00:00.01

Cache More
SQL> exec dbms_output.put_line( cached( 'SYS' ) ); 29339 PL/SQL procedure successfully completed.

Elapsed: 00:00:01.21
SQL> exec dbms_output.put_line( cached( 'SYS' ) ); 29339 PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
SQL> exec dbms_output.put_line( cached( 'SCOTT' ) ); 6 PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00

#3 Standby Just got better

Standby Database Logical Standby was


Limited in type support But was always open for business

Physical Standby was


Easy But considered not useful day to day

Standby Database Logical Standby has


XMLType support DBMS_RLS & DBMS_FGA support TDE support

Active Data Guard: Develop & Test on Standby DB


Production Database

Use physical standby database for development & testing


Developers, Testers

Preserves zero data loss in test/dev mode

Flashback DB to back-out changes & use as standby

Standby Database

Eliminates cost of idle DR system

Active Data Guard: Report & Backup from Standby DB


Production Database

Offload reporting to standby


Reporting Standby Database

Simultaneously available for recovery

Offload backups to standby

Complete database and fast incremental backups

Backups

Improves performance on production database

Active Data Guard More than a Standby


Disaster protection only
Recovery mode only Used in disaster only Manual intensive Low ROI

Disaster and performance protection


Simultaneous read and recovery Use daily in testing and production Automated High ROI

#4 Real Application Testing

Real Application Testing Database Replay


Recreate actual production database workload Capture production workload incl. concurrency Replay workload in test with production timing Analyze & fix issues before production
Middle Tier

Production Environment

Test (RAC) Environment`

Oracle DB servers

Capture DB Workload

Replay DB Workload

Storage

#5 Smaller more secure DMP files

Datapump
COMPRESSION
ALL, DATA_ONLY, METADATA_ONLY, NONE

$ expdp / directory=tmp dumpfile=uncompressed.dmp compression=NONE schemas=ops\$tkyte Export: Release 11.1.0.6.0 - Production on Friday, 21 September, 2007 12:23:26 . . exported "OPS$TKYTE"."BIG_TABLE" . . exported "OPS$TKYTE"."T" 24.57 MB 6.791 MB 250000 rows 67945 rows

$ expdp / directory=tmp dumpfile=compressed.dmp compression=ALL schemas=ops\$tkyte Export: Release 11.1.0.6.0 - Production on Friday, 21 September, 2007 12:23:58 . . exported "OPS$TKYTE"."BIG_TABLE" . . exported "OPS$TKYTE"."T" $ ls -l /tmp/*compressed.dmp -rw-r-----rw-r----1 ora11gr1 ora11gr1 4124672 Sep 21 12:24 /tmp/compressed.dmp 1 ora11gr1 ora11gr1 33136640 Sep 21 12:23 /tmp/uncompressed.dmp 3.110 MB 762.1 KB 250000 rows 67945 rows

Datapump

ENCRYPTION
All Data_only Metadata_only None Encrypted_columns_only

REUSE_DUMPFILES Ability to use DML error logging features


DATA_OPTIONS parameter

PARTITION_OPTIONS
None Departition Merge

#6 Virtual Columns

Virtual Columns Create Table Alter Table Add Column Are column expressions
Expressions involving other columns in table Constants Deterministic functions

Ease of use and Optimizer enhancement

Virtual Columns
ops$tkyte%ORA11GR1> /* ops$tkyte%ORA11GR1> create table emp ops$tkyte%ORA11GR1> as ops$tkyte%ORA11GR1> select all_objects.*, object_id sal, round(dbms_random.value( 1000, 100000 )) comm ops$tkyte%ORA11GR1> ops$tkyte%ORA11GR1> / from all_objects

ops$tkyte%ORA11GR1>
ops$tkyte%ORA11GR1> */ ops$tkyte%ORA11GR1> exec dbms_stats.gather_table_stats( user, 'EMP' )

PL/SQL procedure successfully completed.

Virtual Columns
ops$tkyte%ORA11GR1> select avg( sal+comm ) avg_comp, avg(sal) avg_sal, avg(comm) avg_comm from emp; AVG_COMP AVG_SAL AVG_COMM 50555.261

---------- ---------- ---------85376.9437 34821.6827

ops$tkyte%ORA11GR1> select count(case when sal+comm > 85376.9437 then 1 end) above_comp, 2 3 4 count(case when sal count(case when from emp; ABOVE_SAL ABOVE_COMM 33830 34036 > 34821.6827 then 1 end) above_sal , comm > 50555.261 then 1 end) above_comm

ABOVE_COMP 33957

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

Virtual Columns
ops$tkyte%ORA11GR1> select * from emp where sal > 34821.6827; -------------------------------------------------------------------| Id | |* | Operation 0 | SELECT STATEMENT 1 | | Name | Rows | | Bytes | Cost (%CPU)| Time 3893K| 3893K| 309 309 (1)| 00:0 (1)| 00:0 -------------------------------------------------------------------| 34673 | | 34673 | TABLE ACCESS FULL| EMP

-------------------------------------------------------------------ABOVE_COMP 33957 ABOVE_SAL ABOVE_COMM 33830 34036

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

Virtual Columns
ops$tkyte%ORA11GR1> select * from emp where comm > 50555.261; -------------------------------------------------------------------| Id | |* | Operation 0 | SELECT STATEMENT 1 | | Name | Rows | | Bytes | Cost (%CPU)| Time 3811K| 3811K| 309 309 (1)| 00:0 (1)| 00:0 -------------------------------------------------------------------| 33943 | | 33943 | TABLE ACCESS FULL| EMP

-------------------------------------------------------------------ABOVE_COMP 33957 ABOVE_SAL ABOVE_COMM 33830 34036

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

Virtual Columns
ops$tkyte%ORA11GR1> select * from emp where sal+comm > 85376.9437; -------------------------------------------------------------------| Id | |* | Operation 0 | SELECT STATEMENT 1 | | Name | Rows | | | | Bytes | Cost (%CPU)| Time 381K| 381K| 309 309 (1)| 00:0 (1)| 00:0 -------------------------------------------------------------------3398 | 3398 | TABLE ACCESS FULL| EMP

-------------------------------------------------------------------ABOVE_COMP 33957 ABOVE_SAL ABOVE_COMM 33830 34036

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

Virtual Columns
ops$tkyte%ORA11GR1> ALTER TABLE emp ADD (comp AS (sal+comm));

Table altered.
ops$tkyte%ORA11GR1> exec dbms_stats.gather_table_stats( user, 'EMP', method_opt=> 'for columns comp' ); PL/SQL procedure successfully completed.

Virtual Columns
ops$tkyte%ORA11GR1> select * from emp where sal+comm > 85376.9437; -------------------------------------------------------------------| Id | |* | Operation 0 | SELECT STATEMENT 1 | | Name | Rows | | Bytes | Cost (%CPU)| Time 3975K| 3975K| 309 309 (1)| 00:0 (1)| 00:0 -------------------------------------------------------------------| 33927 | | 33927 | TABLE ACCESS FULL| EMP

-------------------------------------------------------------------ABOVE_COMP 33957 ABOVE_SAL ABOVE_COMM 33830 34036

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

#7 Partitioning just got better

Partitioning

Composite Completely Virtual Column Partitioning Partition by Reference Interval Partitioning

Enhanced Partitioning
Partition (or index) on virtual (computed) columns New composite partitioning
Range Range List 11g 11g List
9i

Hash
8i

11g

11g

RANGE-RANGE
Order Date by Order Value

LIST-RANGE
Region by Order Value

LIST-LIST
Region by Customer Type

Partitioning by REFERENCE
Table ORDERS

...
Jan 2006 Feb 2006

...

RANGE(order_date) Primary key order_id

Partitioning key inherited through PK-FK relationship Avoids redundant storage, maintenance of order_date

Table LINEITEMS

...
Jan 2006 Feb 2006

RANGE(order_date) ... Foreign key order_id

Partitioning Automation
New INTERVAL partitioning
Automatically creates a new partition when data outside the existing range is first inserted
E.g., monthly partitions, automatic new partition first day of the month

ORDERS

Jul

Aug

Sep

Composite partitioning: interval, interval-list, intervalhash, and interval-range Automates partition management

Sep 1 2007

Partitioning
ops$tkyte%ORA11GR1> create table audit_trail 2 3 4 5 6 7 ) partition by range(ts) interval (numtodsinterval(1,'day')) store in (users, example ) ( ts data timestamp, varchar2(30)

8
9 10 11

(partition p0 values less than


(to_date('22-sep-2007','dd-mon-yyyy')) ) /

Table created.

Partitioning
ops$tkyte%ORA11GR1> select partition_name, tablespace_name, high_value 2 3 from user_tab_partitions where table_name = 'AUDIT_TRAIL';

PARTITION_ TABLESPACE HIGH_VALUE ---------- ---------- ---------------------------------P0 USERS TIMESTAMP' 2007-09-22 00:00:00'

Partitioning
ops$tkyte%ORA11GR1> insert into audit_trail 2 3 4 5 / select sysdate+rownum, 'x' from all_users where rownum <= 5

5 rows created.

Partitioning
ops$tkyte%ORA11GR1> select partition_name, tablespace_name, high_value 2 3 from user_tab_partitions where table_name = 'AUDIT_TRAIL';

PARTITION_ TABLESPACE HIGH_VALUE ---------- ---------- ---------------------------------P0 USERS TIMESTAMP' 2007-09-22 00:00:00'

SYS_P66
SYS_P67 SYS_P68 SYS_P69

EXAMPLE
USERS EXAMPLE USERS

TIMESTAMP' 2007-09-23 00:00:00'


TIMESTAMP' 2007-09-24 00:00:00' TIMESTAMP' 2007-09-25 00:00:00' TIMESTAMP' 2007-09-26 00:00:00'

SYS_P70

EXAMPLE

TIMESTAMP' 2007-09-27 00:00:00'

6 rows selected.

Partitioning
ops$tkyte%ORA11GR1> select partition_name, tablespace_name, high_value 2 3 from user_tab_partitions where table_name = 'AUDIT_TRAIL';

PARTITION_ TABLESPACE HIGH_VALUE ---------- ---------- ------------------------------P0 USERS TIMESTAMP' 2007-09-22 00:00:00'

Partitioning
ops$tkyte%ORA11GR1> insert into audit_trail values ( add_months(sysdate,12), 'x' ); 1 row created. ops$tkyte%ORA11GR1> select partition_name, tablespace_name, high_value 2 3 from user_tab_partitions where table_name = 'AUDIT_TRAIL';

PARTITION_ TABLESPACE HIGH_VALUE ---------- ---------- ------------------------------P0 SYS_P180 USERS EXAMPLE TIMESTAMP' 2007-09-22 00:00:00' TIMESTAMP' 2008-11-10 00:00:00'

Partitioning
ops$tkyte%ORA11GR1> insert into audit_trail values ( add_months(sysdate,6), 'x' ); 1 row created. ops$tkyte%ORA11GR1> select partition_name, tablespace_name, high_value 2 3 from user_tab_partitions where table_name = 'AUDIT_TRAIL';

PARTITION_ TABLESPACE HIGH_VALUE ---------- ---------- ------------------------------P0 SYS_P181 SYS_P180 USERS EXAMPLE EXAMPLE TIMESTAMP' 2007-09-22 00:00:00' TIMESTAMP' 2008-05-10 00:00:00' TIMESTAMP' 2008-11-10 00:00:00'

#8 The long awaited pivot

Pivot
ops$tkyte%ORA11GR1> select deptno, 2 3 sum( decode( job, 'CLERK', sal ) ) clerk, sum( decode( job, 'SALESMAN', sal ) ) salesman,

4
5 6 7 8

sum( decode( job, 'MANAGER', sal ) ) manager,


sum( decode( job, 'ANALYST', sal ) ) analyst, sum( decode( job, 'PRESIDENT', sal ) ) president from emp group by deptno

9
10

order by deptno
/ DEPTNO 10 CLERK 1300 SALESMAN MANAGER 2450 ANALYST PRESIDENT 5000

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

20
30

1900
950 5600

2975
2850

6000

Pivot
ops$tkyte%ORA11GR1> select * 2 3 from (select deptno, job, sal from emp ) e

4
5 6 7 8

pivot( sum(sal) for job in


( 'CLERK', 'SALESMAN', 'MANAGER', 'ANALYST', 'PRESIDENT' ) ) order by deptno / DEPTNO 10 20 'CLERK' 'SALESMAN' 1300 1900 'MANAGER' 2450 2975 6000 'ANALYST' 'PRESIDENT' 5000

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

30

950

5600

2850

#9 Flashback Data Archive

Flashback Data Archive


Total Data Recall
Select * from orders AS OF Midnight 31-Dec-2004

Archive Tables

User Tablespaces

Flashback Data Archive

Tamper-proof data archive Efficient storage and retrieval of undo Keep data for months, years, decades! Fast access to even very old data View data, versions of rows as of any time Control data retention time, purging of data

Oracle 11g Database

#10 Finer Grained Dependency Tracking

Finer Grained Dependency Tracking Fewer Invalidations


Add to a specification so what Add/Drop/Modify a column so what Holds true with view modifications too Change a synonym pointer so what Replace a procedure so what

Finer Grained Dependency Tracking


ops$tkyte%ORA10GR2> create or replace package p1 2 3 4 5 end; / as function f return number;

Package created.

ops$tkyte%ORA10GR2> create or replace package p2


2 3 4 end; as g_global number := p1.f;

Package created.

Finer Grained Dependency Tracking


ops$tkyte%ORA10GR2> select object_name, status 2 3 from user_objects where object_name like 'P_'; STATUS VALID

OBJECT_NAME P1

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

P2

VALID

Finer Grained Dependency Tracking


ops$tkyte%ORA10GR2> create or replace package p1 2 3 4 5 6 end; / as function f return number; procedure p;

Package created.

ops$tkyte%ORA10GR2> select object_name, status


2 3 from user_objects where object_name like 'P_'; STATUS VALID INVALID

OBJECT_NAME P1 P2

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

Finer Grained Dependency Tracking


ops$tkyte%ORA11GR1> create or replace package p1 2 3 4 5 6 end; / as function f return number; procedure p;

Package created.

ops$tkyte%ORA11GR1> select object_name, status


2 3 from user_objects where object_name like 'P_'; STATUS VALID VALID

OBJECT_NAME P1 P2

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

Finer Grained Dependency Tracking


ops$tkyte%ORA10GR2> create table t ( x int, y int ); Table created. ops$tkyte%ORA10GR2> create or replace procedure p

2
3 4 5 6

as
begin for x in ( select x, y from t ) loop null;

7
8 9 end; /

end loop;

Procedure created. ops$tkyte%ORA10GR2> select status from user_objects where object_name = 'P';

STATUS
------VALID

Finer Grained Dependency Tracking


ops$tkyte%ORA10GR2> alter table t add z int; Table altered.

ops$tkyte%ORA10GR2> select status from user_objects where object_name = 'P';


STATUS ------INVALID

ops$tkyte%ORA11GR1> select status from user_objects where object_name = 'P';


STATUS ------VALID

Finer Grained Dependency Tracking


ops$tkyte%ORA10GR2> alter procedure p compile; Procedure altered. ops$tkyte%ORA10GR2> alter table t drop column z;

Table altered.
ops$tkyte%ORA10GR2> select status from user_objects where object_name = 'P'; STATUS

------INVALID ops$tkyte%ORA11GR1> select status from user_objects where object_name = 'P'; STATUS

------VALID

#11 OLTP Table Compression

Oracle Advanced Compression


Oracle 9i compresses data only during bulk load; useful for DW and ILM Oracle 11g compresses w/ inserts, updates Trade some cpu for disk & i/o efficiency Compress large application tables Transaction processing, data warehousing Compress all data types: structured, unstructured Savings cascade to all db copies: test, dev, standby, mirrors, archiving, backup, etc.

<Insert Picture Here>

Q&A

Вам также может понравиться