330 likes | 489 Views
Chapter 8. Indexes. Indexes Increase Query Speed. An index is a database object used primarily to improve the performance of SQL queries The function of a database index is similar to an index in the back of a book A book index associates a topic with a page number
E N D
Chapter 8 Indexes
Indexes Increase Query Speed • An index is a database object used primarily to improve the performance of SQL queries • The function of a database index is similar to an index in the back of a book • A book index associates a topic with a page number • When you’re locating information in a book, it’s usually much faster to inspect the index first, find the topic of interest, and identify associated page numbers • If there were no index, you would have to inspect every page of the book to find information
Indexes Consume Resources • Keep in mind that the index isn’t free • Consumes disk space • Index must be maintained when table is inserted/updated/deleted • Before creating an index, make sure that it’s beneficial • If the optimizer never decides to use the index, then the index unnecessarily consumes database resources
Aspects to Consider Before Creating an Index • Type of index • Table column(s) to include • Whether to use a single column or a combination of columns • Special features such as parallelism, turning off logging, compression, invisible indexes, and so on • Uniqueness • Naming conventions • Tablespace placement • Initial sizing requirements and growth • Impact on performance of SELECT statements (improvement) • Impact on performance of INSERT, UPDATE, and DELETE statements • Global or local index, if the underlying table is partitioned
Types of Indexes • B-tree • B-tree cluster • Hash cluster • Function-based • Indexed virtual column • Global partitioned • Local partitioned • Reverse key • Key compressed • Bitmap • Bitmap join • Domain
Index Management Guidelines • Add indexes judiciously. Test first to determine quantifiable performance gains. • Use the correct type of index. • Use a separate tablespace(s) for indexes (separate from tablespaces used for tables). • When creating primary-key constraints or unique-key constraints, specify the tablespace for the index. • Let the index inherit its storage properties from the tablespace. • Use consistent naming standards. • Don’t rebuild indexes unless you have a solid reason to do so. • Monitor your indexes, and drop indexes that aren’t used. • Before dropping an index, consider marking it as unusable or invisible. • Create indexes on foreign-key columns.
Deciding which Columns to Index • Define a primary key constraint for each table that results in an index automatically being created on the columns specified in the primary key. • Create unique key constraints on non-null column values that are required to be unique (different from the primary key columns). This results in an index automatically being created on the columns specified in unique key constraints. • Explicitly create indexes on foreign key columns • Create indexes on columns used often as predicates in the WHERE clause of frequently executed SQL queries.
Estimating the Space an Index will Consume (before creating it) SQL> set serverout on SQL> exec dbms_stats.gather_table_stats(user,'CUST'); SQL> variable used_bytes number SQL> variable alloc_bytes number SQL> exec dbms_space.create_index_cost( 'create index cust_idx2 on cust(first_name)', - :used_bytes, :alloc_bytes ); SQL> print :used_bytes SQL> print :alloc_bytes
Creating an Index • Default index type in Oracle is a B-tree (balanced tree) index • Use the CREATE INDEX statement • Examples: SQL> create index d_sources_idx1 on d_sources(d_source_id); SQL> create index d_sources_idx1 on d_sources(d_source_id) tablespace dim_index;
Creating Concatenated Indexes • Oracle allows you to create an index that contains more than one column • Effective when you often use multiple columns in the WHERE clause when accessing a table create table inv( inv_name varchar2(30) ,cust_name varchar2(30));
Factors to Consider with Concatenated Indexes • If columns are often used together in the WHERE clause, consider creating a concatenated index. • If a column is also used (in other queries) by itself in the WHERE clause, place that column at the leading edge of the index (first column defined). • Keep in mind that Oracle can still use a lagging edge index (not the first column defined) if the lagging column appears by itself in the WHERE clause (see the next few paragraphs here for details).
Implementing Function-Based Indexes • In most situations (not all), when a function is used on a column in a WHERE clause, Oracle will ignore the index. • Example: SQL> select emp_name from emp where UPPER(emp_name) = 'DAVE'; • In the prior line of code, even if there is an index on emp_name, Oracle will ignore the index • Solution, create a function-based index: SQL> create index user_upper_idx on emp(upper(emp_name));
Consider Using a Virtual Column with an Index instead of Function-Based Index • Using a virtual column in combination with an index provides you with an alternative method for achieving performance gains when using SQL functions on columns in the WHERE clause. • Add the virtual column: SQL> alter table cust add(up_name generated always as (UPPER(first_name)) virtual); • Now create an index on the virtual column: SQL> create index cust_vidx1 on cust(up_name); • Performance can often be much better than a function-based index.
Creating Unique Key Indexes • See Chapter 7 for Primary Key constraints and the associated index automatically created when you specify an PK • Difference between a PK and UK index is that the UK index doesn’t enforce uniqueness for NULL values inserted into the table. In other words, you can insert the value NULL into the indexed column for multiple rows. • Ensures that non-NULL values are unique when you insert or update columns in a table. SQL> create unique index inv_uidx1 on inv(sku_id);
Creating Bitmap Indexes • Bitmap indexes are recommended for columns with a relatively low number of distinct values (low cardinality). • Should not use bitmap indexes on OLTP databases with high INSERT/UPDATE/DELETE activities, due to of locking issues. • Used extensively in data warehouse environments on fact table foreign key columns that map to dimensional lookup primary key columns. SQL> create bitmap index reg_idx1 on locations(region);
Creating Bitmap Join Indexes • Bitmap join indexes store the results of a join between two tables in an index. • Bitmap indexes are beneficial because they avoid joining tables to retrieve results. • Syntax: create bitmap index <index_name> on <fact_table> (<dimension_table.dimension_column>) from <fact_table>, <dimension_table> where <fact_table>.<foreign_key_column> = <dimension_table>.<primary_key_column>;
Reverse-Key Indexes • Say you’re using a sequence to populate the primary key of a table and realize that this can cause contention on the leading edge of the index because the index values are nearly similar. • You want to spread out the inserts into the index so that the inserts more evenly distribute values across the index structure. SQL> create index inv_idx1 on inv(inv_id) reverse; Index value Reverse key value ------------- -------------------- 100 001 101 101 102 201
Creating Key-Compressed Indexes • Efficiently compresses index in which many rows have the same values in one or more indexed columns. • Use the COMPRESS N clause to create a compressed index. SQL> create index cust_cidx1 on cust(last_name, first_name) compress 2; • The prior line of code instructs Oracle to create a compressed index on two columns (LAST_NAME and FIRST_NAME).
Parallelizing Index Creation • In large database environments where you’re attempting to create an index on a table that is populated with many rows, you may be able to reduce the time it takes to create the index by using the PARALLEL clause. create index inv_idx1 on inv(inv_id) parallel 2 tablespace inv_mgmt_data;
Avoiding Redo Generation When Creating an Index • Increase speed at which index is created by turning off redo generation with the NOLOGGING clause. • Doing so has these implications: • The redo isn’t generated that would be required to recover the index in the event of a media failure. • Subsequent direct-path operations also won’t generate the redo required to recover the index information in the event of a media failure. create index inv_idx1 on inv(inv_id, inv_id2) nologging tablespace inv_mgmt_index;
Implementing Invisible Indexes • You know from experience that sometimes when an index is added to a third-party application, this can cause performance issues and also can be a violation of the support agreement with the vendor. • You want to implement an index in such a way that the application won’t ever use the index. • You can create the index as invisible and then explicitly instruct a query (outside of the 3rd party application) to use the index via a hint: SQL> create index inv_idx1 on inv(inv_id) invisible; SQL> alter system set optimizer_use_invisible_indexes=true; SQL> select /*+ index (inv INV_IDX1) */ inv_id from inv where inv_id=1;
Placing Indexes in Tablespaces Separate from Tables • DBAs debate the merits of separating tables and indexes into different tablespaces. • Here are some valid reasons to separate index tablespaces from table tablespaces: • You may want to implement different physical storage characteristics (such as extent size) for tables and indexes, and you prefer to allow the table and index to inherit their storage attributes from the tablespace. • You prefer to have the option of being able to back up, restore, and recover table and index tablespaces separately. • When running maintenance reports, you find it easier to manage tables and indexes when the reports have sections separated by tablespace.
Placing Indexes in Tablespaces Based on Extent Size • If you know how large an index may initially be or what its growth requirements are, consider placing the index in a tablespace that is appropriate in terms of the size of the tablespace and the size of the extents. • Examples: create tablespace inv_idx_small datafile '/ora01/dbfile/O11R2/inv_idx_small01.dbf' size 100m extent management local uniform size 128k segment space management auto; -- create tablespace inv_idx_med datafile '/ora01/dbfile/O11R2/inv_idx_med01.dbf' size 1000m extent management local uniform size 4m segment space management auto;
Creating Indexes with No Segments • You can instruct Oracle to create an index that will never be used and won’t have any extents allocated to it via the NOSEGMENT clause: SQL> create index cust_idx1 on cust(first_name) nosegment; • Even though this index will never be used, you can instruct Oracle to determine if the index might be used by the optimizer via the _USE_NOSEGMENT_INDEXES initialization parameter—for example: SQL> alter session set "_use_nosegment_indexes"=true; SQL> set autotrace trace explain; SQL> select first_name from cust where first_name = 'JIM'; • Purpose: If you have a very large index that you want to create without allocating space, to determine if the index would be used by the optimizer, creating an index with NOSEGMENT allows you to test that scenario. If you determine that the index would be useful, you can drop the index and re-create it without the NOSEGMENT clause.
Index Maintenance Activities • Renaming an index • Displaying the DDL for an index • Rebuilding an index • Setting indexes to be unusable • Dropping an index
Renaming an Index • Might need to rename an index because it was initially created with a name that doesn’t conform to your index naming standards. SQL> alter index user1_index rename to emp_idx1;
Displaying Code to Re-create an Index • Sometimes you might find yourself in a situation where you don’t have the DDL to recreate indexes, and you need to view the index creation script. • Use DBMS_METADAT.GET_DDL to get index creation statement. SQL> set long 10000 SQL> select dbms_metadata.get_ddl('INDEX','INV_IDX1') from dual;
Reasons for Rebuilding an Index • The index has become corrupt. • You want to modify storage characteristics, such as changing the tablespace. • An index that was previously marked as unusable now needs to be rebuilt to make it usable again. SQL> alter index inv_idx1 rebuild;
Making Indexes Unusable • If you’ve identified an index that is no longer being used, you can mark it as UNUSABLE. From that point forward, Oracle won’t maintain the index, nor will the optimizer consider the index for use in SELECT statements. SQL> alter index inv_idx1 unusable; • Consider also that you can modify an index to be invisible. In this case, the index is still maintained, but is not used by the query optimizer.
Monitoring Index Usage • You may find yourself in a situation where you’re maintaining a database, and you need to determine which indexes are being not used, the idea being that you can drop unused indexes to free up space and resources. SQL> alter index F_DOWN_DOM_FK9 monitoring usage;
Dropping an Index • If an index is not being used, then you might want to drop it so that it doesn’t consume space and resources. SQL> drop index inv_idx1; • Consider making the index invisible before dropping it. • Also consider marking the index as unusable before dropping it. • These features allow you to put the index back in place more quickly if it is determined that the index is being used by the application.
Summary • Indexes are critical database objects used to improve the performance of SQL queries. • You should be familiar with Oracle index types and indexing strategies.