CHAPTER 7 Tables and Constraints Logical Progression of Steps in Creating a Database Environment 1. Install Oracle database binaries (Chapter 1) 2. Create database (Chapter 2) 3. Establish a way to manage your environment (Chapter 3) 4. Create and manage tablespaces and datafiles (Chapter 4) 5. Understand and manage control files, online redo logs, and archiving (Chapter 5) 6. Create users and establish basic security (Chapter 6) 7. Create database objects (Chapter 7, 8, 9) Tables and Constraints • A table is the basic storage container for data in a database. You create and modify the table structure via Data Definition Language (DDL) statements such as CREATE TABLE and ALTER TABLE • You access and manipulate table data via Data Manipulation Language (DML) statements (INSERT, UPDATE, DELETE, MERGE, and SELECT) • A constraint is a mechanism for enforcing that data adheres to business rules • Examples of constraints: Primary key uniqueness, not null values, relationships between data in tables (foreign keys) Understanding Table Types • Heap-organized • Temporary • Index-organized (IOT) • Partitioned • Materialized view (MV) • Clustered • External • Nested • Object Understanding Data Types • Character • Numeric • Date/Time • RAW • ROWID • LOB Note: For Oracle Database 11g and lower, 4,000 was the largest size allowed for a VARCHAR2 or NVARCHAR2 data type. In Oracle Database 12c and higher, you can specify up to 32,767 characters in a VARCHAR2 or NVARCHAR2 data type. Prior to 12c, if you wanted to store character data larger greater than 4,000 characters, the logical choice was a CLOB (see the section “LOB,” later in this chapter, for more details). Index-organized (IOT) Choosing Table Features • If a column always contains numeric data, make it a • • • • number data type. If you have a business rule that defines the length and precision of a number field, then enforce it; for example, NUMBER(7,2). If you don’t have a business rule, make it NUMBER(38). For character data that is of variable length, use VARCHAR2 (and not VARCHAR). Use DATE and TIMESTAMP data types appropriately. Consider setting the physical attribute PCTFREE to a value higher than the default of 10% if the table initially has rows inserted with null values that are later updated with large values. Index-organized (IOT) Choosing Table Features (continued) • Most tables should be created with a primary key. • Create a numeric surrogate key to be the primary key for each table. Populate the surrogate key from a sequence. • Create a unique key for the logical business key; a recognizable combination of columns that makes a row unique. • Define foreign keys where appropriate. • Consider special features such as virtual columns, readonly, parallel, compression, no logging, and so on. Index-organized (IOT) Choosing Table Features (continued) • Use standards when naming tables, columns, constraints, • • • • • • • triggers, indexes, and so on. If you have a business rule that specifies the maximum length of a column, then use that length, as opposed to making all columns VARCHAR2(4000). Specify a separate tablespace for the table and indexes. Let tables and indexes inherit storage attributes from the tablespaces. Create primary-key constraints out of line. Create comments for the tables and columns. If a column should always have a value, then enforce it with a NOT NULL constraint. Create audit-type columns, such as CREATE_DTT and UPDATE_DTT , that are automatically populated with default values and/or triggers. Creating a Heap-organized Table • Use the CREATE TABLE statement to create tables create table d_sources( d_source_id number not null, source_type varchar2(32), create_dtt date default sysdate not null, update_dtt timestamp(5) ); More Complex Create Table Statement create table operating_systems( operating_system_id number(19, 0) not null, version varchar2(50), os_name varchar2(256), release varchar2(50), vendor varchar2(50), create_dtt date default sysdate not null, update_dtt date, constraint operating_systems_pk primary key (operating_system_id) using index tablespace inv_mgmt_index ) tablespace inv_mgmt_data ; Implementing Virtual Columns • A virtual column is based on one or more existing • • • • columns from the same table and/or a combination of constants, SQL functions, and user-defined PL/SQL functions Virtual columns aren’t stored on disk Evaluated at runtime when the SQL query executes Virtual columns can be indexed and can have stored statistics Tip: Consider using an indexed virtual column instead of using a function based index Advantages of Virtual Columns • You can create an index on a virtual column. Internally, Oracle creates a function-based index. • You can store statistics in a virtual column that can be used by the cost-based optimizer (CBO). • Virtual columns can be referenced in WHERE clauses. • Virtual columns are permanently defined in the database. There is one central definition of such a column Virtual Column Example create table inv( inv_id number ,inv_count number ,inv_status generated always as ( case when inv_count <= 100 then 'GETTING LOW' when inv_count > 100 then 'OKAY' end) ); Virtual Column Considerations • You can only define a virtual column on a regular heap- organized table. You can’t define a virtual column on an index-organized table, an external table, a temporary table, object tables, or cluster tables. • Virtual columns can’t reference other virtual columns. • Virtual columns can only reference columns from the table in which the virtual column is defined. • The output of a virtual column must be a scalar value (a single value, not a set of values). Implementing Invisible Columns • Starting with Oracle Database 12c, you can create invisible columns. When a column is invisible, it cannot be viewed via • DESCRIBE command • SELECT * (to access all of a table’s columns) • %ROWTYPE (in PL/SQL) • Describes within an Oracle Call Interface (OCI) • However, the inivisible column can be accessed if explicitly specified in a SELECT clause or referenced directly in a DML statement (INSERT, UPDATE, DELETE, or MERGE). • Invisible columns can also be indexed (just like visible columns). Reasons for Read-Only Tables • The data in the table is historical and should never be updated in normal circumstances. • You’re performing some maintenance on the table and want to ensure that it doesn’t change while it’s being updated. • You want to drop the table, but before you do, you want to place it in read-only mode to better determine if any users are attempting to update the table. SQL> alter table inv read only; SQL> alter table inv read write; 12c Autoincrementing (Identity) Column • Starting with Oracle Database 12c, you can define a column that is automatically populated and incremented when inserting data. • This feature is ideal for automatically populating primary key columns. • Prior to Oracle Database 12c, you would have to create a sequence manually and then access the sequence when inserting into the table. Sometimes, DBAs would create triggers on tables to simulate an autoincrementing column based on a sequence (see Chapter 9 for details). 12c Autoincrementing Column • You define an autoincrementing (identity) column with the GENERATED AS IDENTITY clause. This example creates a table with primary key column that will be automatically populated and incremented: create table inv( inv_id number generated as identity ,inv_desc varchar2(30 char)); alter table inv add constraint inv_pk primary key (inv_id); • Now, you can populate the table without having to specify the primary key value: insert into inv (inv_desc) values ('Book'); insert into inv (inv_desc) values ('Table'); Avoiding Extent Allocation Delays When Creating Tables • Starting with Oracle Database 11g R2, with non-partitioned heap-organized tables created in locally managed tablespaces, the initial segment creation is deferred. • Allows for a faster installation of applications that have a large number of tables and indexes; this improves installation speed, especially when you have thousands of objects. • As a DBA, your space usage reports may initially confuse you when you notice that there is no space allocated for objects. • The creation of the first row will take a slightly longer time than in previous versions (because now Oracle allocates the first extent based on the creation of the first row). For most applications, this performance degradation is not noticeable. Avoiding Extent Allocation Delays When Creating Tables (continued) SQL> create table f_regs(reg_id number, reg_name varchar2(200)); SQL> select count(*) from user_segments where segment_name='F_REGS'; COUNT(*) ---------0 SQL> insert into f_regs values(1,'BRDSTN'); 1 row created. SQL> select count(*) from user_segments where segment_name='F_REGS'; COUNT(*) ---------1 • You can disable the deferred segment creation feature by setting the database initialization parameter DEFERRED_SEGMENT_CREATION to FALSE • Deferred segment generation also applies to partitioned tables and indexes. An extent will not be allocated until the initial record is inserted into a given extent. Parallel SQL Execution • For large table operations, consider using PARALLEL create table inv_apr_10 parallel 2 as select * from inv where create_dtt >= '01-apr-10' and create_dtt < '01-may10'; Compressing Data for Direct Path Loading • Use the COMPRESS clause to enable compression either when creating, altering, or moving an existing table. • Load data via a direct path mechanism such as CREATE TABLE…AS SELECT or INSERT /*+ APPEND */. • Prior to Oracle Database 11g R2, basic compression was referred to as DSS compression and enabled via the COMPRESS FOR DIRECT_LOAD OPERATION clause. This syntax is deprecated in Oracle Database 11g R2 and higher. Compressing Data for Direct Path Loading (continued) create table regs_dss compress as select reg_id, reg_name from regs; • The prior statement creates a table with compressed data in it. • Any subsequent direct path–load operations will also load the data in a compressed format. • You can use either the COMPRESS clause or the COMPRESS BASIC clause to enable the basic table compression feature. The COMPRESS clause and COMPRESS BASIC clause are synonymous. Compressing Data for All DML • Use the COMPRESS FOR OLTP clause when creating a table to enable data compression when using regular DML statements to manipulate data create table regs (reg_id number ,reg_name varchar2(2000) ) row store compress advanced; Note 10g and 11g syntax for table compression is slightly different, refer to Oracle’s old documentation for details. Compressing Data at the Column Level • The Oracle Exadata product allows for column level compression (hybrid columnar compression) • To enable hybrid columnar compression, when creating a table, use either the COMPRESS FOR QUERY or the COMPRESS FOR ARCHIVE clause create table f_regs( reg_id number ,reg_desc varchar2(4000)) compress for query; Compressing Data at the Column Level (continued) • These levels are listed here from the lowest level of column level compression to the highest level: • COMPRESS FOR QUERY LOW • COMPRESS FOR QUERY HIGH • COMPRESS FOR ARCHIVE LOW • COMPRESS FOR ARCHIVE HIGH • COMPRESS FOR QUERY is appropriate for bulk load operations on heap-organized tables that are infrequently updated • COMPRESS FOR ARCHIVE maximizes the degree of compression and is more appropriate for data that is stored for long periods of time and will not be updated Maximizing Data Loading Speeds • Set the table’s logging attribute to NOLOGGING;, this minimizes the generation redo for direct path operations (this feature has no effect on regular DML operations). • Use a direct path loading feature, such as the following: • INSERT /*+ APPEND */ on queries that use a subquery for determining which records are inserted. • INSERT /*+ APPEND_VALUES */ on queries that use a VALUES clause. • CREATE TABLE…AS SELECT Creating a Table from a Query • Create table as select (CTAS) create table cwp_user_profile_101910 as select * from cwp_user_profile; create table cwp_user_profile_101910 nologging tablespace staging_data parallel 2 as select * from cwp_user_profile_tab; Modifying a Table • Renaming the table • Adding a column • Altering a column • Renaming a column • Dropping a column Obtaining the Needed Lock • In Oracle Database 11g and higher, set the DDL_LOCK_TIMEOUT parameter. • Avoids the ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired SQL> alter session set ddl_lock_timeout=100; Reasons for Renaming a Table • To make the table conform to standards • To better determine whether the table is being used before you drop it SQL> rename inv_mgmt to inv_mgmt_old; Adding a Column • Requirements often change after initially creating the table SQL> alter table inv add(inv_count number); Altering a Column • Requirements often change after the column definitions are defined and implemented SQL> alter table inv modify inv_desc varchar2(256); Renaming a Column • Sometimes requirements change, and you want to modify the column name to better reflect what the column is used for. • If you’re planning to drop a column, it doesn’t hurt to rename the column first to better determine whether any users or applications are accessing the column. SQL> alter table inv rename column inv_count to inv_amt; Dropping a Column • Sometimes column are initially created and never used, or requirements change after the table was created SQL> alter table inv drop (inv_name); Displaying Table DDL • Query the data dictionary • Use the exp and imp utilities • Use Data Pump • Use the DBMS_METADATA package • Example using DBMS_METADATA: SQL> set long 10000 SQL> select dbms_metadata.get_ddl('TABLE','INV') from dual; Dropping a Table • Consider renaming the table before dropping it SQL> drop table emp; • Use PURGE to drop table permanently (remove it from the recyclebin): SQL> drop table emp purge; Undropping a Table • When you drop a table (without PURGE clause), the table is renamed, this is known as placing it in the recyclebin • View recylebin: SQL> show recyclebin • To undrop a table: SQL> flashback table purchases to before drop; Removing Data from a Table Using Delete SQL> delete from inv; SQL> commit; Removing Data from a Table Using Truncate • TRUNCATE is a DDL statement • Oracle automatically commits the statement SQL> truncate table computer_systems; Detecting Table with Significant Free Space Below High Water Mark Using Autotrace 1. SQL> set autotrace trace statistics 2. Run the query that performs the full-table scan. 3. Compare the number of rows processed to the number of logical I/Os (memory and disk accesses). Detecting Table with Significant Free Space Below High Water Mark Using DBMS_SPACE dbms_space.space_usage( segment_owner => user, segment_name => 'INV', segment_type => 'TABLE', ........ Removing Free Space Below High Water Mark • Use a TRUNCATE statement (removes all data from the table) • Use ALTER TABLE ... SHRINK SPACE • Use ALTER TABLE ... MOVE SQL> alter table inv enable row movement; SQL> alter table inv shrink space; SQL> alter table parties move tablespace mts; Creating a Temporary Table • Sometimes applications need a temporary table for the duration of the session • Used to hold data temporarily by the application during the session • ON COMMIT PRESERVE ROWS • ON COMMIT DELETE ROWS create global temporary table today_regs on commit preserve rows as select * from f_registrations where create_dtt > sysdate - 1; Creating an Index-Organized Table • IOTs are efficient when most of the columns in the table are part of the primary key • IOTs uses a b-tree index structure create table prod_sku (prod_sku_id number, sku varchar2(256), create_dtt timestamp(5), constraint prod_sku_pk primary key(prod_sku_id) ) organization index including sku pctthreshold 30 tablespace inv_mgmt_data overflow tablespace mts; Managing Constraints • Primary key • Unique key • Foreign key • Check • Not null Creating Primary-Key Constraints • Guarantees uniqueness for primary key columns • Most tables should always include a primary key • Example: create table dept( dept_id number, dept_desc varchar2(30), constraint dept_pk primary key (dept_id) using index tablespace prod_index); Enforcing Unique Key Values • Use unique keys to enforce uniqueness on columns that aren’t part of the primary key • Example: create table dept( dept_id number ,dept_desc varchar2(30) constraint dept_desc_uk1 unique using index tablespace prod_index); Creating Foreign-key Constraints • Foreign-key constraints are used to ensure that a column value (or multiple columns) is contained within a defined list of values in a column or columns in another table • Used to enforce that a child record has a corresponding record in a parent table • Parent table must contain a PK or UK constraint on parent table columns referenced in the child table foreign key columns • Example: create table emp( emp_id number, name varchar2(30), dept_id constraint emp_dept_fk references dept(dept_id)); Checking for Specific Data Conditions • Check constraints work well for enforcing a column value is of a specific value • Works well for static, fairly small list of know values, for example Y or N, 0 or 1, and so on • Example: CREATE table emp( emp_id number, emp_name varchar2(30), st_flg number(1) constraint "st_flg must be 0 or 1" check (st_flg in (0,1)) ); Enforcing Not Null Conditions • Business requirements may dictate that a column always contain a value • Example: create table emp( emp_id number, emp_name varchar2(30) constraint emp_name_nn not null); Disabling Constraints • Sometimes you will need to disable constraints on a table • Easier than dropping and re-creating • Prior to truncating a table that has a primary key referenced by a foreign key; in this scenario, first disable the constraints and then truncate, then re-enable constraints • Example: SQL> alter table f_sales disable constraint f_sales_fk1; Summary • DBAs must know how to create and maintain tables and constraints • Several new 11g features related to tables were introduced in this chapter • Tables are the basic object used to store data • Constraints enforce business rules related to data integrity