• Aucun résultat trouvé

2-9. Indexing a Virtual Column

Dans le document Oracle Database 11g (Page 69-72)

Problem

You’re currently using a function-based index but need better performance. You want to replace the function-based index with a virtual column and place an index on the virtual column.

■ Note The virtual column feature requires Oracle Database 11g or higher.

Solution

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. For example, suppose you have this query:

SELECT first_name FROM cust

WHERE UPPER(first_name) = 'DAVE';

Normally, the optimizer will ignore any indexes on the column FIRST_NAME because of the SQL function applied to the column. There are two ways to improve performance in this situation:

• Create a function-based index (see Recipe 2-8 for details).

• Use a virtual column in combination with an index.

This solution focuses on the latter bullet. First a virtual column is added to the table that encapsulates the SQL function:

SQL> alter table cust add(up_name generated always as (UPPER(first_name)) virtual);

Next an index is created on the virtual column:

SQL> create index cust_vidx1 on cust(up_name);

This creates a very efficient mechanism to retrieve data when referencing a column with a SQL function.

How It Works

You might be asking this question: “Which performs better, a function-based index or an indexed virtual column?” In our testing, we were able to create several scenarios where the virtual column performed better than the function-based index. Results may vary depending on your data.

The purpose of this recipe is not to convince you to immediately start replacing all function-based indexes in your system with virtual columns; rather we want you to be aware of an alternative method for solving a common performance issue.

CHAPTER 2 ■ CHOOSING AND OPTIMIZING INDEXES

A virtual column is not free. If you have an existing table, you have to create and maintain the DDL required to create the virtual column, whereas a function-based index can be added, modified, and dropped independently from the table.

Several caveats are associated with virtual columns:

• You can define a virtual column only 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 reference columns only 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).

To view the definition of a virtual column, use the DBMS_METADATA package to view the DDL associated with the table. If you’re selecting from SQL*Plus, you need to set the LONG variable to a value large enough to show all data returned:

SQL> set long 10000;

SQL> select dbms_metadata.get_ddl('TABLE','CUST') from dual;

Here’s a partial snippet of the output showing the virtual column details:

"UP_NAME" VARCHAR2(30) GENERATED ALWAYS AS (UPPER("FIRST_NAME")) VIRTUAL VISIBLE) SEGMENT CREATION IMMEDIATE

You can also view the definition of the virtual column by querying the

DBA/ALL/USER_IND_EXPRESSIONS view. If you’re using SQL*Plus, be sure to issue a SET LONG command first—for example:

SQL> SET LONG 500

SQL> select index_name, column_expression from user_ind_expressions;

The SET LONG command in this example tells SQL*Plus to display up to 500 characters from the COLUMN_EXPRESSION column, which is of type LONG.

2-10. Avoiding Concentrated I/O for Index

Problem

You use 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. This leads to multiple inserts into the same block, which causes contention. You want to spread out the inserts into the index so that the inserts more evenly distribute values across the index structure. You want to use a reverse-key index to accomplish this.

Solution

Use the REVERSE clause to create a reverse-key index:

SQL> create index inv_idx1 on inv(inv_id) reverse;

You can verify that an index is reverse-key by running the following query:

SQL> select index_name, index_type from user_indexes;

Here’s some sample output showing that the INV_IDX1 index is reverse-key:

INDEX_NAME INDEX_TYPE

--- --- INV_IDX1 NORMAL/REV

USERS_IDX1 NORMAL

■ Note You can’t specify REVERSE

for a bitmap index or an index-organized table.

How It Works

Reverse-key indexes are similar to B-tree indexes except that the bytes of the index key are reversed when an index entry is created. For example, if the index values are 100, 101, and 102, the reverse-key index values are 001, 101, and 201:

Index value Reverse key value --- --- 100 001

101 101 102 201

Reverse-key indexes can perform better in scenarios where you need a way to evenly distribute index data that would otherwise have similar values clustered together. Thus, when using a reverse-key index, you avoid having I/O concentrated in one physical disk location within the index during large inserts of sequential values. The downside to this type of index is that it can’t be used for index range scans, which therefore limits its usefulness.

You can rebuild an existing index to be reverse-key by using the REBUILD REVERSE clause—for example:

SQL> alter index f_regs_idx1 rebuild reverse;

Similarly, if you want to make an index that is reverse-key into a normally ordered index, then use the REBUILD NOREVERSE clause:

SQL> alter index f_regs_idx1 rebuild noreverse;

CHAPTER 2 ■ CHOOSING AND OPTIMIZING INDEXES

2-11. Adding an Index Without Impacting Existing

Dans le document Oracle Database 11g (Page 69-72)