SlideShare a Scribd company logo
1 of 17
Download to read offline
Paper #135 / Page 1 
The Art of Indexing in Oracle8i 
Venkat S. Devraj 
IMMEDIENT (formerly Raymond James Consulting) 
Introduction 
In most applications, OLTP or DSS, indexes are one of the most ardently used objects. In spite of this, they are 
highly under-estimated. Creating an index is considered to be a simple and precise science. In my experience, I 
have noted quite a few sites creating indexes with great vigor and finally ending up with one-too-many and not 
knowing which ones deserve to stay and which ones can be eliminated without an adverse impact on queries. And 
of course, there are other sites that tend to seriously under-exploit them, worrying about the possible detrimental 
impact on inserts and deletes. Furthermore, the rich and varied indexing options offered by Oracle8i adds fuel to 
the fire. Be it new full-fledged index types or new index-access paths, indexing is emerging as an art, demanding 
a rock-solid understanding of both concepts and implementation from developers and DBAs. 
Objectives 
The objective of this paper is two-fold : 
· To introduce the various index types and access-paths available in Oracle8i and shed more technical light on 
them; 
· Present specific examples of index-usage at my client-sites to foster better understanding. 
Hopefully, this paper will help an attendee in determining specifically what type of index to create during which 
situation; when an index should be re-built and what kind of access-path should be determined for major DML 
statements, using those indexes. I have intentionally breezed through and at times, even avoided standard “run-of-the- 
mill” commentary about indexes and instead focussed on material not easily available in the manuals. The 
intention of this paper is not to replace the Oracle documentation-set, but to act as a source of reference for real-world 
implementation of indexes. 
Index-types in Oracle8i 
Oracle8i continues to offer the following major index-types : 
· B-Tree indexes 
· Bit-mapped indexes 
In addition, there are the following variations of the B-Tree index (sub-types) : 
· Partitioned indexes 
· Reverse-key indexes 
· Index-organized tables (IOTs) 
· Cluster indexes 
· Function-based indexes (Oracle8i only)
Paper #135 / Page 2 
· Application domain indexes (Oracle8i only) 
Furthermore, you might find the following index-related terms useful : 
· Local and global indexes 
· Pre-fixed and non-prefixed indexes 
· Abstract data-type indexes 
Last but not the least, the following index access-paths are provided : 
· Regular Index/Table lookups : Uses the ROWID from the index to locate a row in the table. 
· Index-only lookups : If all the necessary columns are available in the index itself, the table-lookup is avoided. 
· Index range scans : A range of index keys are scanned to locate the desired key-value. 
· Fast Full Index scans (FFIs) : FFIs allow reading of multiple index blocks to expedite full index scans. Since 
an index is usually smaller than a table, an index full-scan is a much faster alternative to a full table scan, if 
the index includes all required columns. The init.ora parameter db_file_multiblock_read_count determines the 
number of index blocks read in one I/O operation (remember, many operating systems have a 64K upper limit 
on I/O). 
· Parallel Query Option (PQO) “enriched” paths : In Oracle8/8i, PQO is available for all the above access-paths. 
This paper assumes prior knowledge of certain key concepts. Before we start, let’s take a quick peek at those 
concepts : 
· Constraints and index-creation : Declaring primary-key and unique constraints automatically creates an index 
on the concerned columns. The USING INDEX clause of the CREATE and ALTER TABLE commands 
allows more control over this index-creation process. 
· Rule and Cost based optimization : Rule based optimization is still supported in Oracle8i. Oracle8i sites can 
use either RULE, COST or CHOOSE as a value for the OPTIMIZER_MODE init.ora parameter. This setting 
is of paramount importance in the way Oracle8i uses indexes. For example, the rule-based optimizer merges 
indexes if they are non-unique and the predicates used are equality predicates. This is because range-predicates 
with multiple indexes generally require additional processing that would impede performance. 
Under the cost-based optimizer (CBO), this would not necessarily happen if the cost of doing the merge were 
higher than the cost of using multiple non-unique indexes. In addition, certain new index sub-types and access 
paths are available only while using CBO. For example, partitioned indexes and fast full index scans (FFIs). 
With changes in the CBO in almost every new release, never assume that your DML statements are using a 
certain index. Always run an EXPLAIN PLAN on every important DML statement to ensure usage of the 
right indexes. 
· Analyzing of tables and indexes : CBO requires all tables and indexes to be analyzed periodically, especially 
after periods of high DML activity. These statistics are used by CBO to evaluate the “cost” of all available 
access-paths and the path with the lowest cost is selected.
· Usage of hints to force index-selection : Under both rule or cost based optimization, certain hints may be 
provided to DML statements to specifically select a certain index. This functionality is provided to override 
the optimizer, in case the access-path selected by it is sub-optimal. Syntax for hints are very similar to 
comments, except for the addition of a plus (+) symbol. If a hint is provided incorrectly, the optimizer ignores 
the hint. 
Example : SELECT /*+ INDEX(table_a, index_a) */ id, name FROM table_a; 
Index-related hints supported by Oracle8i include INDEX, INDEX_DESC, INDEX_COMBINE, 
INDEX_FFS and PARALLEL_INDEX for retrieving rows from indexes in an ascending order, descending 
order, combining bit-mapped indexes using boolean logic, prompting the optimizer to use the Fast Full Index 
(FFI) scan in lieu of a full-table scan and inducing a parallel-scan of an index (using PQO) respectively. 
B-Tree Indexes : Everybody’s most favorite index! 
This is one of the earliest indexing options available in Oracle. And we are all absolutely familiar with this index-type, 
right ? OK, let’s have a quick show-of-hands : how many of us here today, understand or remember a B-Tree 
structure ? Believe me, good usage of these “basic” indexes requires a good understanding of how B-Trees 
indexes operate. Implementation of B-Trees are a little unique in every application in terms of it’s height and 
order. However, the basic behavior is the same. Let’s take a quick practical look at how B-Trees indexes have 
been implemented in Oracle8. 
M 
G S 
A B C 
D E F 
H I J K 
L 
N O P 
Q R 
T U V 
Root/branch 
nodes 
Leaf nodes 
Fig. 1a : A simplistic B-tree implementation (height : 2 and order : 2) [Branch/leaf nodes read to locate “R” are displayed 
Paper #135 / Page 3 
in bold] 
B-Trees are an excellent way of looking up pointers to large information with minimal number of disk-reads. In a 
B*Tree, all information is either a branch/root node or a leaf-node. The final information (ROWIDs and keys) are 
always stored in a leaf (-node). Upto 16 columns can comprise the key in Oracle7.x, whereas in Oracle8.x, it is 32 
columns. Furthermore, a key cannot be greater than 1/3rd the size of the database block (violating this restriction 
would result in the ORA-01450 error). A leaf may contain multiple physical rows. The leaves are always present
only at the last “level”. A B-Tree is a “balanced tree”, because every leaf is equi-distant from the root-node. It 
takes the same time to access any row in any given leaf. Fig. 1a is a poor man’s picture of a B-Tree 
implementation. Anyhow, it clearly indicates the root, the branches and the leaves. Every tree has a certain order 
and height. The order is the number of “branches” for every node of the tree. The height is the number of levels 
the tree contains. Ideally the height has to be minimal, since the number of disk-reads required to get information 
is proportionate to the height of the tree. For example in fig. 1a, in order to get “R”, two disk-reads are required 
(“M” at the root-node and “S” at the second-level node). Thus, here a minimum of three reads would be required 
to locate a key (two reads at the root/branch level and the third at the leaf-node level). It is to be borne in mind, 
that each read may be a logical read or a physical read, depending on how the index is laid out. If a single read 
operation places the required number of blocks in memory, subsequent reads would be performed off memory, 
else they would need to go to disk. The height is inversely proportionate to the order. The higher the order, the 
lower the height (termed as a “flat” tree). An important objective in any B-Tree implementation is to increase the 
branches and reduce the height, thereby ensuring speedy access to the leaves. 
A major challenge with a B-Tree implementation occurs during INSERTs, DELETEs and UPDATEs. During 
every INSERT, the key has to be inserted appropriately within the right leaf. Every key has one and only one 
place within the tree. If the leaf is already full and cannot accommodate any additional keys, then the leaf has to 
be split into two. Now, there are two options available : 
1. if the new key value is the biggest (of all the keys existing in the old leaf block), then the total keys are split in 
a 99:1 ratio, wherein only the new key is placed in the new leaf block, whereas the rest of the (old) keys are 
retained within the old leaf block (including all deleted keys). 
2. if the new key value is not the biggest, then the total keys are split in a 50:50 ratio, wherein each of the leaf 
Paper #135 / Page 4 
blocks (old and new) would absorb half the keys of the original leaf. 
This split has to be propagated upwards to the parent node by means of a new entry to point to the new leaves. If 
the parent node happens to be full, then the node has to be split into two and it’s parent has to be notified of the 
split. God forbid, if that parent is full, as well! Thus, a split may be propagated all the way up to the root-node, 
itself. Remember, each split is costly involving physical disk I/O. Additionally, prior to splitting, Oracle has to 
seek and find an empty block to accommodate the split. The following steps are taken to do so : 
1. Seek in the index free-list for a free block. More than one free-list can be defined for an index (via the 
CREATE/ALTER INDEX commands). Free-lists for indexes do not aid Oracle in finding an available block 
for accommodating the new key-value being inserted. This is because a key-value cannot be randomly placed 
in the first “free” leaf-block that’s available within the index. The value has to be placed within a specific 
leaf-block after appropriate sorting. Free-lists in indexes are used only during block splitting. Each free-list 
comprises of a linked-list of “empty” blocks. When more than one free-list is defined for an index, the free-list 
allotted to the process is initially scanned for a free block. If none are found, the master free-list is 
checked. 
2. If no free blocks are found, Oracle tries to allocate another extent. If there is no free space in the tablespace, 
Oracle gives an error (ORA-01654). 
3. If a free block is found via either of the above steps, the high watermark for the index is increased. 
4. Use the free block found to perform the split. 
Part of the challenge in creating B-Tree indexes is to avoid splits at runtime or rather, to induce splits during 
index-creation (“pre-splitting”) and take the performance-hit at that point in time, and not during run-time inserts. 
These splits may not be restricted merely to inserts, they may occur during updates, as well.
Let’s take a look at what goes on within Oracle during an indexed-key UPDATE. Index updates differ vastly from 
table updates. In a table update, data is changed within the data-block (assuming there is sufficient space in the 
block for this change to take place). However in an index, when a key is changed, it’s position within the tree has 
to change. Remember, a key has one and only one position within a B-Tree. So when it changes, the old entry has 
to be deleted and a new one has to be created at a new leaf. Chances are, the old entry may never be re-used. 
Because Oracle would reuse a key-entry slot only when the newly inserted key is exactly the same as an old 
(deleted) one, including data-type, length and case. And what are the chances of that happening ? Most 
applications at my client-sites use a sequence to generate NUMBER keys (especially primary keys). Unless they 
are using the RECYCLE option, the sequences do not generate the same number twice. So, the deleted space 
within the index remains unused. This is the reason why during large-scale DELETEs and UPDATEs, the table-size 
Paper #135 / Page 5 
shrinks or at least remains constant, whereas the indexes grow continuously. 
From the above explanation of B-Trees, the following dos and don’ts emerge : 
· Avoid indexing columns, that are subject to high UPDATEs. 
· Avoid indexing multiple columns in tables, that are subject to high DELETEs. If possible, only index the 
primary-key and/or column(s) determining the deletes on such tables. If indexing multiple columns is 
unavoidable, then consider partitioning the tables based on those columns and do a TRUNCATE on each such 
partition (instead of a DELETE). TRUNCATE simulates a drop and re-create of the table and index by re-setting 
the high-water mark, when used with the DROP STORAGE clause. 
· Avoid creating b-tree indexes for columns with low selectivity (less uniqueness). Low selectivity leads to 
dense leaf-blocks, causing large-scale index scans. The higher the uniqueness, the better the performance, 
since range-scans would reduce and maybe even be replaced with an unique scan. 
· Null values are never stored in single-column indexes,. In the case of multi-column indexes, the value is 
stored only if one of the columns is not null. Bear this in mind while constructing IS NULL or IS NOT NULL 
clauses for DML statements. An IS NULL would never induce an index-scan, whereas an unrestrained IS 
NOT NULL would cause a full index range-scan. 
You have heard these advises before, but now the precise logic behind these words of wisdom is apparent. 
The importance of PCTFREE 
For a B-Tree index, PCTFREE determines the extent of a leaf-split. In other words, PCTFREE indicates the 
amount of free-space within a block for “future updates”. However in the case of an index (unlike a table), these 
updates do not make sense, since an update anyway forces a delete and subsequent insert. 
In the case of indexes, PCTFREE plays a role mostly at the time of index-creation. A non-zero value specifies the 
block-splitting ratio. If PCTFREE is set to 20, during index-creation, upto 80% of the leaf may contain key-information. 
However the remaining 20% should be available for future inserts of key-information into that leaf-block. 
This ensures that during run-time inserts, there is minimal overhead in terms of incurring leaf-block splits. 
Even though a higher PCTFREE may cause index-creation time to increase, it prevents the performance-hit from 
being deferred to actual usage time. So, the end-user, who is waiting for a row to be inserted does not incur the 
performance penalty associated with a leaf-block split.
Based on this information, the following points emerge : 
· PCTFREE for an index is used primarily during creation. It is ignored during actual usage. 
· Specify a higher PCTFREE for OLTP applications, if the table is a popular one, incurring a lot of DML 
Paper #135 / Page 6 
changes (via interactive user-screens); 
· Specify a lower PCTFREE, if the index-creation time is critical. This will pack in more rows per leaf-block, 
thereby avoiding the need for further splitting at creation-time. This is of paramount significance to shops, 
that have “24x7” availability requirements. Index-creation in most cases, requires considerable downtime 
(especially if the table is a multi-million row table). Lesser the amount of index-creation time, smaller can be 
the maintenance-window. I have seen this tiny, often unnoticed parameter save around 20% of index-creation 
time. At a high-availability site, an index on a table containing around 11 million rows took me about 80 
minutes to build using PCTFREE of 30 and a parallel degree of 4. The same index on the same table, with 
13.5 million rows took me around 90 minutes to create with a PCTFREE of 0 (without any hardware/software 
enhancements). Nologging (minimal redo) was on during both creations. 
· For any column where the values are constantly increasing, it is probably a good idea to set a very low 
PCTFREE (even, zero). This is because only the rightmost leaf-block will always be inserted into. This will 
make the tree grow towards the right. The leftmost leaves would remain static. So, there is no sense in leaving 
any part of those blocks empty with a non-zero PCTFREE. 
Partitioned indexes 
Partitioned indexes are indexes, which have been horizontally sub-divided based on a specific range of key-values. 
Partitioning allows logically dependent structures to be physically independent. This allows maintenance 
operations to be performed on specific partition, while the others are still available for access. Thus, a specific 
partition may be offline and unavailable, while the other partitions are online and available for access. An index-partition 
may be re-built or recovered with minimal effect on applications. Each index-partition may have 
different storage characteristics and may be created in different tablespaces. Partitioned indexes may be created 
even for non-partitioned tables. 
Partitioned index-related terms 
Global and Local indexes : When an index is partitioned in a similar fashion as the table, in terms of ranges of 
partition-keys, then it is referred to as a local index. In other words, the local index shares the key-ranges with the 
parent table. It would store the keys of only it’s corresponding table-partition. A global index does not have a one-to- 
one correspondence with any table-partition in terms of partition-key ranges. A global index would store rows 
from multiple table-partitions. A local index is also referred to as an equi-partitioned index; whereas a global 
index is also referred to as a non equi-partitioned index. 
For example, a table may be partitioned into 52 segments based on the week-of-year. However, the index might 
be partitioned into 12 segments based on month-of-year. Such an index would be termed a global index. If the 
index were partitioned into 52 segments, it would be referred to as a local index. 
A bit-mapped index on a partitioned table has to be a local index.
Prefixed and non-prefixed indexes : When an index of a partitioned table contains the partition key as the leading 
column, it is termed as a prefixed index. A non-prefixed index does not have partition key columns as the leading 
keys. 
Local pre-fixed indexes should be created, whenever possible. Since they have a one-to-one correspondence with 
the partitioned table, administration is easier. Global pre-fixed indexes theoretically may have a slight 
performance edge at times, since the overhead of accessing large number of indexes is avoided. However 
partition pruning (where the partition key-value specified in the WHERE clause helps Oracle in determining 
which partition might contain the required results and accesses only that partition) helps in super-charging local 
partition access. Even in situations where partition pruning is not possible, parallel access of multiple local 
indexes via PQO may provide higher performance. It is generally more expensive to scan a non-prefixed index, 
compared to a pre-fixed index, since as mentioned earlier, in the case of a pre-fixed index, the optimizer can use 
the partition key-value to scan just the necessary index partitions (rather than all) for a predicate referring to the 
indexed columns. 
Oracle8.x does not support global non-prefixed indexes, since they do not have any practical utility. A global 
index may be split into local indexes or multiple local indexes may be merged into a global one. 
Considering partitioned indexes 
Let me illustrate this “partitioning scenario” with an example. One of my clients is a company providing free e-mail 
via the web. Their users receive a lot of e-mails. When a user deletes a message, the mail-entry is “deleted” 
from the main-messages table and moved to a garbage-bin. This is achieved by setting the garbage-flag to ‘1’ for 
that row in the main table. Only when the user specifically deletes it from his garbage-bin, the mail is permanently 
deleted. Many users set up their account such that once a week, their garbage-bin is automatically purged. So 
every week-end, this huge batch-job was run to delete all rows from the main-table where the garbage-flag = ‘1’. 
Since the garbage-flag column was being used in the WHERE clause of the DELETE, it was part of a regular B-Tree 
index (a bit-mapped index was not used even though the cardinality was low, because the column was 
subject to high updates and another key column was being used as the index-prefix). However, every time it was 
updated to ‘1’, it’s index-entry would be deleted and a new-one would be created. Furthermore, when the record 
would finally be deleted, the index-entry would continue to take up space. Thus the table would not significantly 
grow in size (due to e-mails being deleted and inserted all the time). However the index was growing at an 
incredible rate, taking up large amounts of tablespace area. Finally this problem was solved by replacing the 
design with a “partition-aware” design. 
Consider partitioning indexes : 
· for intense OLTP applications, dealing with a large number of rows. The flexibility in administrating 
Paper #135 / Page 7 
relatively small segments is a great boon. 
· for high-availability (24x7) environments, where the down-time associated with an index-rebuild cannot be 
tolerated 
· for better overall performance. Whenever possible, Oracle8/8i parallelizes scans of partitioned indexes. Also 
partition elimination allows specific partitions to be eliminated from searches based on the key-ranges. This 
vastly expedites index-scans. Finally, partitioning allows an index to be spread out over multiple physical 
tablespaces/data-files, thereby reducing the occurrence of I/O hot-spots.
Do not partition indexes on key-values prone to constant updates, especially if such updates cause partition 
migration, where a row has to be moved from one partition to another. 
Lastly, one frequently question that pops up at client-sites is, how many partitions can be realistically created 
without any performance degradation ? Theory apart (where thousands and thousands of partitions can be 
created), the answer to this question depends on various factors such as system resources (CPUs, memory, I/O 
channels across which the partitions are created, etc.) and varies from site to site. A lot also depends on 
applications and data. If the data lends itself to a “clean” partitioning structure, based on a popular (frequently 
used in most queries) key-column(s), then partitioning across a large number of partitions would be more 
effective, since partition pruning is possible in most situations. However if such a popular key column is not 
available, then utilizing a large number of partitions may cause performance degradation, since multiple partitions 
would need to be frequently visited to retrieve the required values. As such, it is always essential to ensure that 
you select a popular key column as the partitioning key. If such a column does not currently exist, evaluate 
introducing it explicitly (for instance, by denormalizing the table). Additionally, always ensure that there is 
sufficient scope for parallelizing partitioned operations (such as multiple CPUs, data spread across multiple 
disks/controllers, etc.). I have seen partitioning to be very effective in certain situations, when the number of 
partitions do not exceed a few hundreds. After that, the law of diminishing returns comes into play, as system 
resources get saturated and performance begins to stink. 
Reverse-key indexes 
A reverse-key index is primarily a b-tree index, where the bytes of key-values are stored in a reversed order. By 
reversing the keys, index entries are spread more evenly throughout the b-tree. This is very useful in an OPS 
(Oracle Parallel Server) environment, where contention for the same leaf-blocks might cause inter-instance 
“pinging” to occur, thereby affecting performance adversely due to excessive disk I/O. 
Paper #135 / Page 8 
Examples of a reversed key are as follows : 
ADAMSON NOSMADA 
1558 8551 
Dates in a reverse-key index are stored by reversing the seven bytes contained in a DATE data-type. 
Considering reverse-key indexes 
In late 1996, at a client-site in Bombay, India, our team was implementing a Custodial Services system. We faced 
a major performance-impediment with the share-certificates table; especially when the clients would acquire a 
large number of share-certificates with sequential numbering. We had created the right index on the table and had 
ensured that the index was indeed, being used. However, even a pure index-access would take unusually long : at 
least 15 seconds more than what we expected (based on our experiments with other similar tables). Finally we 
figured out that storing those sequential certificate numbers caused the index to be lop-sided. In other words, 
some of the leaves would be dense (heavily populated), whereas some of them would be sparse, based on the
series of share-certificates we obtained. Most DML activity would focus on these dense leaves, thereby creating 
“hot-spots” on the index. By hot-spots, I mean index-activity would be much more for these few leaf-blocks, 
compared to the others. Since there would usually be only one disk-controller accessing those blocks, all activity 
would have to be serialized, thereby adversely affecting response-time and throughput. 
In such a situation, reverse-key indexes would have been a boon. However we were using Oracle7 v7.3 at that 
time, where the feature was still not available. We lived with the situation for a while. Finally, we circumvented 
the situation by reversing the values within the application. We had two columns in the table, a column that would 
store the share-certificate number as it was and a primary-key column, which would store the same share-certificate 
in a reversed order. We wrote a stored function, which would accept the actual share-certificate as an 
input parameter and return the reversed number, which would subsequently be inserted in the table as the primary 
key. This gave us a relatively “well-balanced” index. 
The same concept applies to any value that increases in spurts : sequential numbers, date and time columns, etc. 
Increasing in spurts indicates a scenario where the value monotonously increases, then there is not much activity 
for a while, thereby creating “gaps” in the values; then the value constantly increases again. Such columns would 
be prime candidates for using the Oracle8/8i reverse-key indexes. Also, in fast-growing tables where indexes are 
built on sequential values (such as a primary-key index), and large-scale deletes frequently occur, the index may 
begin to “slide”. A sliding index is one that continuously grows towards the right (newer rows being inserted), 
while the left-portion is constantly being deleted (older rows being purged). The left-portions of the tree 
comprises of nulls or empty leaf-nodes, whereas the tree is expanding to the right, thus appearing to “slide”. 
Reversing the index may halt the right-oriented growth (due to constantly increasing key-values) and make the 
growth more balanced by placing the reversed key-values in all directions (left and right). Additionally, 
partitioning the index (on a “rolling window” scheme) and truncating older partitions (rather than deleting) would 
help in eliminating the large number of empty leaf-blocks. 
One question might come to your mind : how did we manage to figure out that our index was indeed lop-sided ? 
We used an “ALTER SESSION SET EVENTS” command to understand the index-structure better. This 
command is mentioned in more detail in Appendix A. 
Some caveats to bear in mind while using reverse-key indexes : 
· Reverse key indexes are not effective when used in range scans 
· Reverse key indexes are prone to all the restrictions of regular b-tree indexes, such as avoiding excessive 
Paper #135 / Page 9 
DML activity, periodic re-building, etc. (since they are merely a variation of B-Trees). 
Index-organized tables (IOTs) 
Index-organized tables are tables, where the rows are stored in a B-Tree structure, based on the primary-key 
value. A primary key definition is mandatory for an IOT. In Oracle8 v8.0.x, IOTs do not have rowids (this 
restriction is removed in 8i via “logical rowids” [explained below]). An index entry is expected to be terse to 
remain effective. Since a full-fledged row may be too big to retain index-effectiveness, Oracle8/8i provides the 
PCTTHRESHOLD clause to indicate a percentage of the total block-size. All non-primary key columns that cause 
a row to grow beyond the size of this percentage are moved to an “overflow” tablespace.
Considering index-organized tables 
A short while ago, I was part of a team, building a large data-warehouse for a major investment company in 
Oracle8/8i. In the data-warehouse, we had a bunch of code-tables, acting as dimension tables. In the first iteration 
of the physical design, we built all those code-tables as regular tables with two columns : the code-id and the 
description. We had a primary key index on the code-id. We also cached some of these tables and their indexes in 
the Oracle SGA. 
However with more familiarity with Oracle8i, we observed that these code-tables were prime candidates for using 
the index-organized feature. Since there was only one index on each of these tables, we could use the primary-key 
to structure the rows in these tables in a B-Tree format. In the second iteration of the physical design, we re-defined 
most of our code-tables as index-organized tables. This change brought us space-savings to the tune of 
35%. From around 800 MB for both regular-tables and the primary key indexes, the space-usage has dropped 
down to approximately 520 MB for the index-organized tables. These space-savings affect not only disk-usage, 
but also memory usage (since many of the tables were cached). That was true space-savings for us, since memory 
is always at a premium! Soon after we could consider caching additional information within the SGA, without 
having to expand it. 
Needless to add, this space-saving was obtained due to absence of the physical rowids and any indexes on the 
index-organized tables. This example illustrates that tables such as code-tables or certain master tables, not prone 
to frequent changes are ideal for using the index-organized feature of Oracle8/8i. This useful option brings 
substantial space-savings to the table, especially when going from a regular table with an index comprising of 
most of the columns in the table (built that way to exploit the “index-only lookup” access-path) to an index-organized 
Paper #135 / Page 10 
table. 
Some caveats with IOTs in Oracle8 versions (prior to 8i): 
· The table structure cannot be altered 
· Non-primary key indexes cannot be created 
· Absence of rowids might cause problems while migrating Oracle7 applications to Oracle8, if the application 
DML explicitly depends on rowids 
Note that all the above restrictions have been eliminated in Oracle8i, allowing IOT usage to be more practical. 
The new “logical rowids” contain the primary key of the referenced row, instead of a physical location within the 
database. This means that if a row is moved to a new location, the logical rowid would still contain a valid 
reference to the row and would not need to be updated. To retain the speed of conventional rowids, logical rowids 
also contain a physical location hint, which can be used to optimize performance. If an index is created on a field 
other than the primary key (note that IOTs support secondary indexes in 8i), Oracle8i will create a logical index 
using logical rowids to reference the table rows. 
One caveat that does remain even in 8i is row-chaining, which is inevitable with large-sized rows.
Bit-mapped indexes 
The biggest difference between a b-tree index and a bit-mapped index is that the former encourages indexing on 
columns with high selectivity, whereas the latter encourages low selectivity. This is primarily due to inherent 
structural differences. A bit-mapped index creates a binary bit-map stream, consisting of 1s and 0s for every 
distinct key-value. It uses distinct bits (of every byte) to create these binary steams. Due to application of bit-level 
binary arithmetic, large-numbers of rows can be processed at high speeds. Also, if a table has multiple low-cardinality 
columns, then bit-map indexes may be created on each of those columns. Multiple indexes in turn will 
be merged using bit-level boolean logic resulting in very fast index-access times. In the case of compound 
indexes, a bit-mapped index can have upto a maximum of 14 columns in Oracle7.x and upto 30 columns in 
Oracle8/8i (always 2 less than B*Tree indexes). Bit-mapped indexes are available only with CBO. 
Bit-mapped indexes are stored in compressed form, thereby causing huge space-savings. Oracle uses a proprietary 
compression algorithm, capable of handling even high-cardinality columns (this is useful in scenarios such as a 
star-schema, where the dimension tables have very high cardinality). On a data-warehouse at a client-site, a B-tree 
index on a column with 2 distinct values on a table with 12 million rows took up around 184Mb, whereas a bit-mapped 
index on the same column now takes up a mere 3Mb – a direct saving of more than 98% disk-space! 
The star-transformation access-path (introduced in Oracle8) uses bit-mapped indexes to merge results from 
multiple dimension tables with a large fact table to produce extremely fast query results, without having to 
perform an expensive Cartesian product as in a regular star query. 
An example of a good candidate for a bit-mapped index would be the “marital status” column on the customer 
table in a data-mart for the Sales department. The marital status column would have a domain consisting of the 
following 4 values : single, married, divorced, widowed. The logical view of a bit-mapped index created on this 
column is represented in table 2a : 
Paper #135 / Page 11 
'RPDLQ 9DOXH 
&XVWRPHU /DVW 
1DPH 
6LQJOH 0DUULHG 'LYRUFHG :LGRZHG %LWPDS 
SDWWHUQ 
6PLWK      
:KLWH      
%URZQ      
%ODFN      
Table 2a : column “Bit-map pattern” provides the logical index-key pattern [remember a bit may either be on (1) or off (0) ] 
From a physical standpoint, each bit-map stream consists of a header portion and a body, wherein the header 
comprises of the key-value and the beginning and ending rowids for a range of rows having that key-value. The 
body comprises of the actual bit-map stream for the same range of rows. The size of the body is guaranteed to be 
50% or less of the initialization parameter DB_BLOCK_SIZE. Thus, a bitmap may be stored as smaller pieces to 
adhere to this rule. The physical structure is depicted in figure 2b.
Paper #135 / Page 12 
Header body 
{Key-value} {begin ROWID} {end ROWID} {bit-map stream} 
In Oracle7 : 
Key-value Begin ROWID End ROWID Bit-map stream 
‘Salaried’ 12345211.3415.5642 12345211.3415.5822 0101010000111 
In Oracle8/8i : 
Key-value Begin ROWID End ROWID Bit-map stream 
‘Salaried’ AAAAgmAADAAAAE8AAB AAAAgoAADAAAAFVAAC 01110111011 
Figure 2b: Physical view of a bit-mapped index 
A few things to consider while creating a bit-map index : 
· Is the table often queried by this column ? If not, is an index really needed on the column ? 
· How many rows are present in the table ? A small table (a few thousand rows) does not warrant a bit-mapped 
index. 
· Does the column have low cardinality ? If not, is the degree of uniqueness high ? Degree of uniqueness may 
be depicted as “number of unique values / total number of rows in the table * 100”. 
· Is the column prone to frequent DML (non-batch, OLTP DML) ? If so, it’s probably a good idea to leave it 
alone or maybe use it as a secondary column to create a regular B-tree index (the leading column should have 
high selectivity). 
· Are there multiple columns in the table, which are good candidates for bit-mapped indexes ? If so, would such 
columns be frequently referred in the WHERE clause of queries ? If so, there are high chances of the bit-mapped 
indexes on these columns being merged by CBO to provide high query throughput. 
· Is the data in the table subject to frequent changes simultaneously by multiple users ? If so, a bit-mapped 
index may not be convenient. Bit-mapped indexes restrict concurrency, due to the entire bit-map being locked 
during a single DML operation affecting any row in the range of rows represented by the bit-map. This could 
potentially cause hundreds of rows to be locked by a single DML statement, intending to affect a single row. 
This is not an issue during parallel DML operations affecting partitioned tables, since index-maintenance 
during such parallel DML occurs at the partition-level. As such, a single index partition is not subjected to 
parallelism, thus leading to concurrency problems. 
Function-based indexing 
This new feature introduced in Oracle8i allows functions to be indexed and used in SQL statements. Earlier 
Oracle releases expressly disabled index-usage when functions were utilized on the key column. However now, 
SQL or user-defined functions can be indexed. For instance, a query such as the following would benefit 
tremendously from function-based indexes : 
SQL SELECT * FROM names WHERE INITCAP(name) LIKE ‘Bill%’;
Paper #135 / Page 13 
An index can be created on a function as follows : 
CREATE SQL INDEX upper_nm_idx01 ON names(INITCAP(name)) 
TABLESPACE tblspc_nm STORAGE(storage_clause); 
Now, applications can issue case-insensitive queries such as the following : 
SQL SELECT * FROM name WHERE name LIKE ‘Bill%’; 
Function-based indexes are also physically stored in a B-tree structure. Please refer to the Oracle8i documentation 
(Oracle8i Concepts) set for further explanation of function-based indexing. 
Application domain indexes 
Application domain indexes are “extended” indexes specific to a certain application domain. These are indexes 
created on non-conventional data-types (domains) such as spatial data and multimedia data-types such as images 
and audio/video streams, spreadsheets and documents, etc. Here, an encapsulated set of code-routines referred to 
as an indextype define the index access and implementation rules for efficient and speedy retrieval of complex 
domains. A data-cartridge is custom-built (via the Oracle8i Data-cartridge Interface) to define the application 
that controls the domain and also defines the inherent structure of the domain index. In other words, all operations 
performed on the index such as range scans, equality checks, etc. need to be explicitly defined. The index can be 
stored inside the database as an index-organized table or externally, as a file. As of Oracle8i v8.1.5, a domain 
index can have only a single column. This column can be a regular scalar data-type or a user-defined attribute of 
an object or a LOB. Information on domain indexes (meta-data) cannot be found in conventional index-related 
views such as DBA_INDEXES, USER_INDEXES, etc. The data-cartridge needs to utilize a specific index meta-data 
management strategy and nominate a pre-defined table to hold the meta-data on domain indexes of a certain 
indextype. Furthermore, wrapper views can be created on top of the meta-data table, if necessary, for additional 
encapsulation. The Oracle8i documentation set (Oracle8i Data Cartridge Developer's Guide) discusses 
application domain indexes in detail. 
Abstract Data-types  their Indexes 
Peek into your abstract data-types with a magnifying glass to identify the scalar data-types, which need indexing. 
Once the abstract type has been broken down into scalars, all the above mentioned indexing rules apply to them. 
Whenever possible, ensure that all your DML specifies the absolute path to these scalar types (else the optimizer 
may not use the right index). By absolute path, I mean “person.name.last_name” and not just “person” even 
“person.name”. 
Considering an index-rebuild 
This is the million-dollar question that many DBAs and developers face : when should one think about re-building 
an application’s indexes ? I have noted that in some organizations, there is a fixed schedule : every 3 months, 
indexes are re-created on tables, undergoing major DML activity. However some of these frequent index-rebuilds 
might be unnecessary or even indexes of less frequently used tables might need to be re-built on a more regular
basis. How does one determine whether they need to be re-built or not ? How does one get actual numbers 
indicating that an index is a candidate for re-building ? By using the command ANALYZE 
INDEX…VALIDATE STRUCTURE. There is another old command called VALIDATE INDEX. This is still 
available in Oracle8/8i (mainly for backward compatibility). Either of these commands populate the 
INDEX_STATS view with meaningful information, that helps in determining whether an index should be re-built 
or not. Please refer to figure 3a for a description of the structure of INDEX_STATS view. 
As is apparent from the structure, DBAs and developers can use the INDEX_STATS view to glean some useful 
information. The statistics in INDEX_STATS are different from the ones in DBA_INDEXES. The statistics in 
DBA_INDEXES are created as a result of using the COMPUTE STATISTICS or ESTIMATE STATISTICS 
options of the ANALYZE command and are used by the cost-based optimizer (CBO). The statistics in 
INDEX_STATS are created by the VALIDATE STRUCTURE option of the ANALYZE command. Another 
important difference is that the ANALYZE STRUCTURE…DELETE STATISTICS command erases statistics in 
DBA_INDEXES; however the statistics in INDEX_STATS are not erased. They get erased only when the index 
is dropped or get re-computed every time the ANALYZE…VALIDATE STRUCTURE command is run. The 
INDEX_STATS view only contains information about one index at any given point in time. Don’t worry about 
old statistics in the INDEX_STATS misleading CBO. CBO does not use the statistics in INDEX_STATS. 
Paper #135 / Page 14 
SQL desc sys.index_stats 
Name Null? Type My comments 
------------------------------- -------- ---- -------------- 
HEIGHT NUMBER Height of tree 
BLOCKS NUMBER 
NAME VARCHAR2(30) 
PARTITION_NAME VARCHAR2(30) 
LF_ROWS NUMBER Leaf rows 
LF_BLKS NUMBER Leaf blocks 
LF_ROWS_LEN NUMBER 
LF_BLK_LEN NUMBER 
BR_ROWS NUMBER Branch rows 
BR_BLKS NUMBER Branch blocks 
BR_ROWS_LEN NUMBER 
BR_BLK_LEN NUMBER 
DEL_LF_ROWS NUMBER Deleted leaves 
DEL_LF_ROWS_LEN NUMBER 
DISTINCT_KEYS NUMBER 
MOST_REPEATED_KEY NUMBER 
BTREE_SPACE NUMBER 
USED_SPACE NUMBER 
PCT_USED NUMBER 
ROWS_PER_KEY NUMBER = 1 for UNIQUE keys 
BLKS_GETS_PER_ACCESS NUMBER 
Figure 3a : description of the INDEX_STATS view in an Oracle8/8i database
Paper #135 / Page 15 
COLUMN name FORMAT a25 -- increase if your index-names are  25 chars 
COLUMN “Total leaf rows” FORMAT 999,999,999,999 
COLUMN “Deleted leaf rows” FORMAT 999,999,999,999 
SELECT name, lf_rows “Total leaf rows”, del_lf_rows “Deleted leaf rows” 
FROM SYS.index_stats 
WHERE name = UPPER(‘enter_index_name’); 
Figure 3b : Query to determine whether index is to be re-built (to be run after ANALYZE INDEX…VALIDATE STRUCTURE 
as a DBA user) 
The query listed in figure 3b provides the total leaf rows and the deleted leaf rows for a given index. If the deleted 
leaf rows seem relatively high compared to the total leaf rows, then the index should be re-built. I use 20% as a 
general rule-of-thumb. If the deleted leaf rows are 20% or more of the total leaf rows, I rebuild the index 
(provided Management waves the green flag!). Also , the command provided in appendix A (ALTER SESSION 
SET EVENTS…) provides additional information to help in deciding whether an index should be rebuilt. 
The REBUILD option 
Starting with Oracle7 7.3, you can use the REBUILD option of the ALTER INDEX command to rebuild indexes. 
You can even use this option to reverse a regular B-Tree index and vice-versa. However a caveat with REBUILD 
is, it does not detect and eliminate index corruption, since it bases the rebuild on the existing index (which might 
be corrupt already). (This holds true even in Oracle8i.) 
ANALYZE TABLE …VALIDATE STRUCTURE CASCADE is the best mechanism to detect index-corruption. 
This command matches each row in the table against all indexes and each row in every index against the table. If 
there is any corruption found, an error message is returned. Subsequently the index may be dropped and re-built 
using the regular DROP and CREATE INDEX commands, rather than the REBUILD option of the ALTER 
INDEX command. 
Conclusion 
By selecting an approach that considers the tips outlined in this paper, you can not only determine when to rebuild 
an index, but also how should the new index be re-built – as a reverse-key index or as a partitioned index or even 
converting a table to an index-organized table. 
Even though Oracle8i has vastly increased the number of indexing options available, B-Tree indexes continue to 
offer the best solution in most cases. As long as they are well-maintained, they provide acceptable performance 
under diverse conditions. However, certain situations, explained above, prove to be ideal for deviating from the 
B-Tree approach and instead using another index type such as bit-mapped, or even variations of the B-Tree such 
as reverse-key, function-based, partitioned or index-organized tables. With the versatile index offerings of 
Oracle8i, there has never been a better time to put on that new thinking cap and look at the process of indexing as 
an art, not a science!
Paper #135 / Page 16 
Appendix A 
Command to dump an index tree structure 
The command “ALTER SESSION SET EVENTS ‘IMMEDIATE TRACE NAME TREEDUMP LEVEL 
level_number’;” dumps the structure of an index b-tree. It gives useful information such as number of levels in 
the index and number of rows per level. Such information helps the DBA to decide whether an index needs to be 
re-built and if so, whether it should be reversed. 
The level_number mentioned in the command above needs to be replaced with an actual number. In 
Oracle8/8i, this level-number is the “object_id” of the index in SYS.DBA_OBJECTS. 
Running the command gives a trace-file in the “user_dump_dest” directory. The trace-file name usually is of the 
form : “ora_SID_NAME_PID#.trc” , where SID_NAME is the ORACLE_SID and PID# is the process-id 
number. Immediately after running this command, you can go to the user_dump_dest directory and run the 
following command : “ls –lt” to pick up the latest trace file. A sample trace-file is provided in fig. 4a. The last 
lines of the dump-file contain the meat of the output (between “begin tree dump” and “end tree dump”). The trace 
file size is directly proportional to the size of the index. 
The file-contents can be interpreted by looking at the number of levels : the branches and the leaves per branch. In 
the sample file provided in fig. 4a, there is only one branch (0x40002b) and 4 leaves (0x4003f0, 0x4003f1, 
0x400b0f and 0x400b10), since the dump was produced for a small index with just 1,819 rows. The rows 
contained in each leaf are 503, 418, 498 and 400 respectively. This indicates that all the leaves are well-balanced 
(in terms of rows per leaf). So, it is a good idea to leave this index alone. However if the rows in some leaves 
seem excessively high compared to other leaves, then probably those leaves are hot-spots and could lead to I/O 
bottlenecks. 
Generally, spurts of sequential values or large delete-jobs cause such uneven distribution of keys. If the culprit is 
merely a huge batch delete job, then probably the situation can be set right by partitioning the table and truncating 
the partition. If partitioning is a not a feasible solution, then re-building the index (without reversing) after such 
batch-deletes would help. Alternatively, if the imbalance is caused by spurts of sequential values being inserted in 
the table, then reversing the key(s) would help.
Paper #135 / Page 17 
Dump file /opt/app/oracle/admin/dv01/udump/ora_dv01_4231.trc 
Oracle8 Enterprise Edition Release 8.1.5.0.0 – Production 
PL/SQL Release 8.1.5.0.0 – Production 
ORACLE_HOME = /opt/app/oracle/product/8.1.5 
System name: sample 
Node name: sample 
Release: 4.0 
Version: 3.0 
Machine: 3446A 
Instance name: dv01 
Redo thread mounted by this instance: 1 
Oracle process number: 7 
Unix process pid: 4231, image: oracledv01 
Wed Jul 14 11:52:11 1999 
*** SESSION ID:(8.69) 1999.07.14.11.52.11.000 
----- begin tree dump 
branch: 0x40002b 4194347 (0: nrow: 4, level: 1) 
leaf: 0x4003f0 4195312 (-1: nrow: 503 rrow: 503) 
leaf: 0x4003f1 4195313 (0: nrow: 418 rrow: 417) 
leaf: 0x400b0f 4197135 (1: nrow: 498 rrow: 498) 
leaf: 0x400b10 4197136 (2: nrow: 400 rrow: 400) 
----- end tree dump 
Figure 4a : Sample trace-file (output of the ALTER SESSION…SET EVENTS command described in appendix A) 
Warning : Please use all commands and scripts provided in this paper at your own risk. I have used all the commands, provided herein, 
multiple times on Oracle8 v8.0.x and v8.1.x databases without any kind of adverse effect. However neither I nor my company, Immedient 
(formerly Raymond James Consulting), warrant that this document is error-free and/or assume any risk associated with it’s usage . Please 
test all scripts and commands on a development database prior to usage on a production database. 
References 
· Oracle8i Server Documentation 
· Oracle 24x7 Tips and Techniques; Venkat S. Devraj; Oracle Press (Osborne/McGraw-Hill); 1999

More Related Content

What's hot

Power ups non standard column names
Power ups non standard column namesPower ups non standard column names
Power ups non standard column namesJohann Krugell
 
SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343
SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343
SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343Edgar Alejandro Villegas
 
Dbms important questions and answers
Dbms important questions and answersDbms important questions and answers
Dbms important questions and answersLakshmiSarvani6
 
Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)
Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)
Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)Alkis Vazacopoulos
 
DBMS_intermediate sql
DBMS_intermediate sqlDBMS_intermediate sql
DBMS_intermediate sqlAzizul Mamun
 
Intro To TSQL - Unit 5
Intro To TSQL - Unit 5Intro To TSQL - Unit 5
Intro To TSQL - Unit 5iccma
 
CIS 336 Wonderful Education--cis336.com
CIS 336 Wonderful Education--cis336.comCIS 336 Wonderful Education--cis336.com
CIS 336 Wonderful Education--cis336.comJaseetha16
 
Intro to relational model
Intro to relational modelIntro to relational model
Intro to relational modelATS SBGI MIRAJ
 
Dbms 9: Relational Model
Dbms 9: Relational ModelDbms 9: Relational Model
Dbms 9: Relational ModelAmiya9439793168
 
A Study of Various Projected Data Based Pattern Mining Algorithms
A Study of Various Projected Data Based Pattern Mining AlgorithmsA Study of Various Projected Data Based Pattern Mining Algorithms
A Study of Various Projected Data Based Pattern Mining Algorithmsijsrd.com
 
1.2M .pdf
1.2M .pdf1.2M .pdf
1.2M .pdfbutest
 
SQL For PHP Programmers
SQL For PHP ProgrammersSQL For PHP Programmers
SQL For PHP ProgrammersDave Stokes
 
Relational Data Model Introduction
Relational Data Model IntroductionRelational Data Model Introduction
Relational Data Model IntroductionNishant Munjal
 

What's hot (20)

Power ups non standard column names
Power ups non standard column namesPower ups non standard column names
Power ups non standard column names
 
Sql ch 1
Sql ch 1Sql ch 1
Sql ch 1
 
Lesson 2.2 abstraction
Lesson 2.2   abstractionLesson 2.2   abstraction
Lesson 2.2 abstraction
 
DBMS_Ch1
 DBMS_Ch1 DBMS_Ch1
DBMS_Ch1
 
SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343
SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343
SQL – The Natural Language for Analysis - Oracle - Whitepaper - 2431343
 
Dbms important questions and answers
Dbms important questions and answersDbms important questions and answers
Dbms important questions and answers
 
Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)
Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)
Constructing the IMPL Flowsheet Using Dia with Python (IMPL-FlowsheetDiaPy)
 
ch3
ch3ch3
ch3
 
DBMS_intermediate sql
DBMS_intermediate sqlDBMS_intermediate sql
DBMS_intermediate sql
 
Intro To TSQL - Unit 5
Intro To TSQL - Unit 5Intro To TSQL - Unit 5
Intro To TSQL - Unit 5
 
CIS 336 Wonderful Education--cis336.com
CIS 336 Wonderful Education--cis336.comCIS 336 Wonderful Education--cis336.com
CIS 336 Wonderful Education--cis336.com
 
Intro to relational model
Intro to relational modelIntro to relational model
Intro to relational model
 
Binary Trees
Binary TreesBinary Trees
Binary Trees
 
Relational Model
Relational ModelRelational Model
Relational Model
 
Dbms 9: Relational Model
Dbms 9: Relational ModelDbms 9: Relational Model
Dbms 9: Relational Model
 
A Study of Various Projected Data Based Pattern Mining Algorithms
A Study of Various Projected Data Based Pattern Mining AlgorithmsA Study of Various Projected Data Based Pattern Mining Algorithms
A Study of Various Projected Data Based Pattern Mining Algorithms
 
1.2M .pdf
1.2M .pdf1.2M .pdf
1.2M .pdf
 
Relational model
Relational modelRelational model
Relational model
 
SQL For PHP Programmers
SQL For PHP ProgrammersSQL For PHP Programmers
SQL For PHP Programmers
 
Relational Data Model Introduction
Relational Data Model IntroductionRelational Data Model Introduction
Relational Data Model Introduction
 

Similar to Art of indexing_in_o8i

8 i index_tables
8 i index_tables8 i index_tables
8 i index_tablesAnil Pandey
 
Getting to know oracle database objects iot, mviews, clusters and more…
Getting to know oracle database objects iot, mviews, clusters and more…Getting to know oracle database objects iot, mviews, clusters and more…
Getting to know oracle database objects iot, mviews, clusters and more…Aaron Shilo
 
Application sql issues_and_tuning
Application sql issues_and_tuningApplication sql issues_and_tuning
Application sql issues_and_tuningAnil Pandey
 
Linked list basics
Linked list basicsLinked list basics
Linked list basicsRajesh Kumar
 
Database Performance Tuning
Database Performance Tuning Database Performance Tuning
Database Performance Tuning Arno Huetter
 
Bank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AE
Bank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AEBank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AE
Bank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AEEngr. Md. Jamal Uddin Rayhan
 
dotnetMALAGA - Sql query tuning guidelines
dotnetMALAGA - Sql query tuning guidelinesdotnetMALAGA - Sql query tuning guidelines
dotnetMALAGA - Sql query tuning guidelinesJavier García Magna
 
Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...
Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...
Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...Massimo Cenci
 
Db performance optimization with indexing
Db performance optimization with indexingDb performance optimization with indexing
Db performance optimization with indexingRajeev Kumar
 
Advance sqlite3
Advance sqlite3Advance sqlite3
Advance sqlite3Raghu nath
 
Sydney Oracle Meetup - indexes
Sydney Oracle Meetup - indexesSydney Oracle Meetup - indexes
Sydney Oracle Meetup - indexespaulguerin
 
Linked List Problems
Linked List ProblemsLinked List Problems
Linked List ProblemsSriram Raj
 
White Paper for OMG! Identifying and Refactoring Common SQL...
White Paper for OMG! Identifying and Refactoring Common SQL...White Paper for OMG! Identifying and Refactoring Common SQL...
White Paper for OMG! Identifying and Refactoring Common SQL...Jeff Jacobs
 
Advance data structure
Advance data structureAdvance data structure
Advance data structureashok kumar
 
Myth busters - performance tuning 102 2008
Myth busters - performance tuning 102 2008Myth busters - performance tuning 102 2008
Myth busters - performance tuning 102 2008paulguerin
 
Building scalable application with sql server
Building scalable application with sql serverBuilding scalable application with sql server
Building scalable application with sql serverChris Adkin
 

Similar to Art of indexing_in_o8i (20)

8 i index_tables
8 i index_tables8 i index_tables
8 i index_tables
 
Getting to know oracle database objects iot, mviews, clusters and more…
Getting to know oracle database objects iot, mviews, clusters and more…Getting to know oracle database objects iot, mviews, clusters and more…
Getting to know oracle database objects iot, mviews, clusters and more…
 
Application sql issues_and_tuning
Application sql issues_and_tuningApplication sql issues_and_tuning
Application sql issues_and_tuning
 
Linked list basics
Linked list basicsLinked list basics
Linked list basics
 
Database Performance Tuning
Database Performance Tuning Database Performance Tuning
Database Performance Tuning
 
Bank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AE
Bank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AEBank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AE
Bank Question Solution-ADBA Previous Year Question for AP, ANE, AME, ADA, AE
 
dotnetMALAGA - Sql query tuning guidelines
dotnetMALAGA - Sql query tuning guidelinesdotnetMALAGA - Sql query tuning guidelines
dotnetMALAGA - Sql query tuning guidelines
 
Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...
Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...
Recipes 8 of Data Warehouse and Business Intelligence - Naming convention tec...
 
Iot
IotIot
Iot
 
Db performance optimization with indexing
Db performance optimization with indexingDb performance optimization with indexing
Db performance optimization with indexing
 
Advance sqlite3
Advance sqlite3Advance sqlite3
Advance sqlite3
 
Codds rules & keys
Codds rules & keysCodds rules & keys
Codds rules & keys
 
Sydney Oracle Meetup - indexes
Sydney Oracle Meetup - indexesSydney Oracle Meetup - indexes
Sydney Oracle Meetup - indexes
 
Linked List Problems
Linked List ProblemsLinked List Problems
Linked List Problems
 
White Paper for OMG! Identifying and Refactoring Common SQL...
White Paper for OMG! Identifying and Refactoring Common SQL...White Paper for OMG! Identifying and Refactoring Common SQL...
White Paper for OMG! Identifying and Refactoring Common SQL...
 
Advance data structure
Advance data structureAdvance data structure
Advance data structure
 
Myth busters - performance tuning 102 2008
Myth busters - performance tuning 102 2008Myth busters - performance tuning 102 2008
Myth busters - performance tuning 102 2008
 
Database Basics
Database BasicsDatabase Basics
Database Basics
 
Building scalable application with sql server
Building scalable application with sql serverBuilding scalable application with sql server
Building scalable application with sql server
 
database.pdf
database.pdfdatabase.pdf
database.pdf
 

More from Anil Pandey

National health policy_2017
National health policy_2017National health policy_2017
National health policy_2017Anil Pandey
 
Class 3-computer-pt3-rev-ws-56
Class 3-computer-pt3-rev-ws-56Class 3-computer-pt3-rev-ws-56
Class 3-computer-pt3-rev-ws-56Anil Pandey
 
Class 3-social-pt3-rev-ws-for-uploading
Class 3-social-pt3-rev-ws-for-uploadingClass 3-social-pt3-rev-ws-for-uploading
Class 3-social-pt3-rev-ws-for-uploadingAnil Pandey
 
Class 3-science-pt3-rev-ws-for-uploading
Class 3-science-pt3-rev-ws-for-uploadingClass 3-science-pt3-rev-ws-for-uploading
Class 3-science-pt3-rev-ws-for-uploadingAnil Pandey
 
Class 3-math-pt3-rev-ws-for-uploading
Class 3-math-pt3-rev-ws-for-uploadingClass 3-math-pt3-rev-ws-for-uploading
Class 3-math-pt3-rev-ws-for-uploadingAnil Pandey
 
Class 3-hindi-pt3-rev-ws-for-uploading
Class 3-hindi-pt3-rev-ws-for-uploadingClass 3-hindi-pt3-rev-ws-for-uploading
Class 3-hindi-pt3-rev-ws-for-uploadingAnil Pandey
 
Class 3-english-pt3-rev-ws-for-uploading
Class 3-english-pt3-rev-ws-for-uploadingClass 3-english-pt3-rev-ws-for-uploading
Class 3-english-pt3-rev-ws-for-uploadingAnil Pandey
 
Apps session wait_tables
Apps session wait_tablesApps session wait_tables
Apps session wait_tablesAnil Pandey
 
Appliance whitepaper 8_i
Appliance whitepaper 8_iAppliance whitepaper 8_i
Appliance whitepaper 8_iAnil Pandey
 
8 isecurity database
8 isecurity database8 isecurity database
8 isecurity databaseAnil Pandey
 

More from Anil Pandey (20)

26 bg2020
26 bg202026 bg2020
26 bg2020
 
National health policy_2017
National health policy_2017National health policy_2017
National health policy_2017
 
Class 3-computer-pt3-rev-ws-56
Class 3-computer-pt3-rev-ws-56Class 3-computer-pt3-rev-ws-56
Class 3-computer-pt3-rev-ws-56
 
Class 3-social-pt3-rev-ws-for-uploading
Class 3-social-pt3-rev-ws-for-uploadingClass 3-social-pt3-rev-ws-for-uploading
Class 3-social-pt3-rev-ws-for-uploading
 
Class 3-science-pt3-rev-ws-for-uploading
Class 3-science-pt3-rev-ws-for-uploadingClass 3-science-pt3-rev-ws-for-uploading
Class 3-science-pt3-rev-ws-for-uploading
 
Class 3-math-pt3-rev-ws-for-uploading
Class 3-math-pt3-rev-ws-for-uploadingClass 3-math-pt3-rev-ws-for-uploading
Class 3-math-pt3-rev-ws-for-uploading
 
Class 3-hindi-pt3-rev-ws-for-uploading
Class 3-hindi-pt3-rev-ws-for-uploadingClass 3-hindi-pt3-rev-ws-for-uploading
Class 3-hindi-pt3-rev-ws-for-uploading
 
Class 3-english-pt3-rev-ws-for-uploading
Class 3-english-pt3-rev-ws-for-uploadingClass 3-english-pt3-rev-ws-for-uploading
Class 3-english-pt3-rev-ws-for-uploading
 
As onew816a
As onew816aAs onew816a
As onew816a
 
Apps session wait_tables
Apps session wait_tablesApps session wait_tables
Apps session wait_tables
 
Appliance whitepaper 8_i
Appliance whitepaper 8_iAppliance whitepaper 8_i
Appliance whitepaper 8_i
 
Appd2 cg
Appd2 cgAppd2 cg
Appd2 cg
 
A85248
A85248A85248
A85248
 
816isdfo
816isdfo816isdfo
816isdfo
 
35 dbatune3
35 dbatune335 dbatune3
35 dbatune3
 
9ias
9ias9ias
9ias
 
9i lin relnotes
9i lin relnotes9i lin relnotes
9i lin relnotes
 
9i hp relnotes
9i hp relnotes9i hp relnotes
9i hp relnotes
 
8 isecurity database
8 isecurity database8 isecurity database
8 isecurity database
 
8i r3 nfs
8i r3 nfs8i r3 nfs
8i r3 nfs
 

Recently uploaded

Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsMehedi Hasan Shohan
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 

Recently uploaded (20)

Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
XpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software SolutionsXpertSolvers: Your Partner in Building Innovative Software Solutions
XpertSolvers: Your Partner in Building Innovative Software Solutions
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 

Art of indexing_in_o8i

  • 1. Paper #135 / Page 1 The Art of Indexing in Oracle8i Venkat S. Devraj IMMEDIENT (formerly Raymond James Consulting) Introduction In most applications, OLTP or DSS, indexes are one of the most ardently used objects. In spite of this, they are highly under-estimated. Creating an index is considered to be a simple and precise science. In my experience, I have noted quite a few sites creating indexes with great vigor and finally ending up with one-too-many and not knowing which ones deserve to stay and which ones can be eliminated without an adverse impact on queries. And of course, there are other sites that tend to seriously under-exploit them, worrying about the possible detrimental impact on inserts and deletes. Furthermore, the rich and varied indexing options offered by Oracle8i adds fuel to the fire. Be it new full-fledged index types or new index-access paths, indexing is emerging as an art, demanding a rock-solid understanding of both concepts and implementation from developers and DBAs. Objectives The objective of this paper is two-fold : · To introduce the various index types and access-paths available in Oracle8i and shed more technical light on them; · Present specific examples of index-usage at my client-sites to foster better understanding. Hopefully, this paper will help an attendee in determining specifically what type of index to create during which situation; when an index should be re-built and what kind of access-path should be determined for major DML statements, using those indexes. I have intentionally breezed through and at times, even avoided standard “run-of-the- mill” commentary about indexes and instead focussed on material not easily available in the manuals. The intention of this paper is not to replace the Oracle documentation-set, but to act as a source of reference for real-world implementation of indexes. Index-types in Oracle8i Oracle8i continues to offer the following major index-types : · B-Tree indexes · Bit-mapped indexes In addition, there are the following variations of the B-Tree index (sub-types) : · Partitioned indexes · Reverse-key indexes · Index-organized tables (IOTs) · Cluster indexes · Function-based indexes (Oracle8i only)
  • 2. Paper #135 / Page 2 · Application domain indexes (Oracle8i only) Furthermore, you might find the following index-related terms useful : · Local and global indexes · Pre-fixed and non-prefixed indexes · Abstract data-type indexes Last but not the least, the following index access-paths are provided : · Regular Index/Table lookups : Uses the ROWID from the index to locate a row in the table. · Index-only lookups : If all the necessary columns are available in the index itself, the table-lookup is avoided. · Index range scans : A range of index keys are scanned to locate the desired key-value. · Fast Full Index scans (FFIs) : FFIs allow reading of multiple index blocks to expedite full index scans. Since an index is usually smaller than a table, an index full-scan is a much faster alternative to a full table scan, if the index includes all required columns. The init.ora parameter db_file_multiblock_read_count determines the number of index blocks read in one I/O operation (remember, many operating systems have a 64K upper limit on I/O). · Parallel Query Option (PQO) “enriched” paths : In Oracle8/8i, PQO is available for all the above access-paths. This paper assumes prior knowledge of certain key concepts. Before we start, let’s take a quick peek at those concepts : · Constraints and index-creation : Declaring primary-key and unique constraints automatically creates an index on the concerned columns. The USING INDEX clause of the CREATE and ALTER TABLE commands allows more control over this index-creation process. · Rule and Cost based optimization : Rule based optimization is still supported in Oracle8i. Oracle8i sites can use either RULE, COST or CHOOSE as a value for the OPTIMIZER_MODE init.ora parameter. This setting is of paramount importance in the way Oracle8i uses indexes. For example, the rule-based optimizer merges indexes if they are non-unique and the predicates used are equality predicates. This is because range-predicates with multiple indexes generally require additional processing that would impede performance. Under the cost-based optimizer (CBO), this would not necessarily happen if the cost of doing the merge were higher than the cost of using multiple non-unique indexes. In addition, certain new index sub-types and access paths are available only while using CBO. For example, partitioned indexes and fast full index scans (FFIs). With changes in the CBO in almost every new release, never assume that your DML statements are using a certain index. Always run an EXPLAIN PLAN on every important DML statement to ensure usage of the right indexes. · Analyzing of tables and indexes : CBO requires all tables and indexes to be analyzed periodically, especially after periods of high DML activity. These statistics are used by CBO to evaluate the “cost” of all available access-paths and the path with the lowest cost is selected.
  • 3. · Usage of hints to force index-selection : Under both rule or cost based optimization, certain hints may be provided to DML statements to specifically select a certain index. This functionality is provided to override the optimizer, in case the access-path selected by it is sub-optimal. Syntax for hints are very similar to comments, except for the addition of a plus (+) symbol. If a hint is provided incorrectly, the optimizer ignores the hint. Example : SELECT /*+ INDEX(table_a, index_a) */ id, name FROM table_a; Index-related hints supported by Oracle8i include INDEX, INDEX_DESC, INDEX_COMBINE, INDEX_FFS and PARALLEL_INDEX for retrieving rows from indexes in an ascending order, descending order, combining bit-mapped indexes using boolean logic, prompting the optimizer to use the Fast Full Index (FFI) scan in lieu of a full-table scan and inducing a parallel-scan of an index (using PQO) respectively. B-Tree Indexes : Everybody’s most favorite index! This is one of the earliest indexing options available in Oracle. And we are all absolutely familiar with this index-type, right ? OK, let’s have a quick show-of-hands : how many of us here today, understand or remember a B-Tree structure ? Believe me, good usage of these “basic” indexes requires a good understanding of how B-Trees indexes operate. Implementation of B-Trees are a little unique in every application in terms of it’s height and order. However, the basic behavior is the same. Let’s take a quick practical look at how B-Trees indexes have been implemented in Oracle8. M G S A B C D E F H I J K L N O P Q R T U V Root/branch nodes Leaf nodes Fig. 1a : A simplistic B-tree implementation (height : 2 and order : 2) [Branch/leaf nodes read to locate “R” are displayed Paper #135 / Page 3 in bold] B-Trees are an excellent way of looking up pointers to large information with minimal number of disk-reads. In a B*Tree, all information is either a branch/root node or a leaf-node. The final information (ROWIDs and keys) are always stored in a leaf (-node). Upto 16 columns can comprise the key in Oracle7.x, whereas in Oracle8.x, it is 32 columns. Furthermore, a key cannot be greater than 1/3rd the size of the database block (violating this restriction would result in the ORA-01450 error). A leaf may contain multiple physical rows. The leaves are always present
  • 4. only at the last “level”. A B-Tree is a “balanced tree”, because every leaf is equi-distant from the root-node. It takes the same time to access any row in any given leaf. Fig. 1a is a poor man’s picture of a B-Tree implementation. Anyhow, it clearly indicates the root, the branches and the leaves. Every tree has a certain order and height. The order is the number of “branches” for every node of the tree. The height is the number of levels the tree contains. Ideally the height has to be minimal, since the number of disk-reads required to get information is proportionate to the height of the tree. For example in fig. 1a, in order to get “R”, two disk-reads are required (“M” at the root-node and “S” at the second-level node). Thus, here a minimum of three reads would be required to locate a key (two reads at the root/branch level and the third at the leaf-node level). It is to be borne in mind, that each read may be a logical read or a physical read, depending on how the index is laid out. If a single read operation places the required number of blocks in memory, subsequent reads would be performed off memory, else they would need to go to disk. The height is inversely proportionate to the order. The higher the order, the lower the height (termed as a “flat” tree). An important objective in any B-Tree implementation is to increase the branches and reduce the height, thereby ensuring speedy access to the leaves. A major challenge with a B-Tree implementation occurs during INSERTs, DELETEs and UPDATEs. During every INSERT, the key has to be inserted appropriately within the right leaf. Every key has one and only one place within the tree. If the leaf is already full and cannot accommodate any additional keys, then the leaf has to be split into two. Now, there are two options available : 1. if the new key value is the biggest (of all the keys existing in the old leaf block), then the total keys are split in a 99:1 ratio, wherein only the new key is placed in the new leaf block, whereas the rest of the (old) keys are retained within the old leaf block (including all deleted keys). 2. if the new key value is not the biggest, then the total keys are split in a 50:50 ratio, wherein each of the leaf Paper #135 / Page 4 blocks (old and new) would absorb half the keys of the original leaf. This split has to be propagated upwards to the parent node by means of a new entry to point to the new leaves. If the parent node happens to be full, then the node has to be split into two and it’s parent has to be notified of the split. God forbid, if that parent is full, as well! Thus, a split may be propagated all the way up to the root-node, itself. Remember, each split is costly involving physical disk I/O. Additionally, prior to splitting, Oracle has to seek and find an empty block to accommodate the split. The following steps are taken to do so : 1. Seek in the index free-list for a free block. More than one free-list can be defined for an index (via the CREATE/ALTER INDEX commands). Free-lists for indexes do not aid Oracle in finding an available block for accommodating the new key-value being inserted. This is because a key-value cannot be randomly placed in the first “free” leaf-block that’s available within the index. The value has to be placed within a specific leaf-block after appropriate sorting. Free-lists in indexes are used only during block splitting. Each free-list comprises of a linked-list of “empty” blocks. When more than one free-list is defined for an index, the free-list allotted to the process is initially scanned for a free block. If none are found, the master free-list is checked. 2. If no free blocks are found, Oracle tries to allocate another extent. If there is no free space in the tablespace, Oracle gives an error (ORA-01654). 3. If a free block is found via either of the above steps, the high watermark for the index is increased. 4. Use the free block found to perform the split. Part of the challenge in creating B-Tree indexes is to avoid splits at runtime or rather, to induce splits during index-creation (“pre-splitting”) and take the performance-hit at that point in time, and not during run-time inserts. These splits may not be restricted merely to inserts, they may occur during updates, as well.
  • 5. Let’s take a look at what goes on within Oracle during an indexed-key UPDATE. Index updates differ vastly from table updates. In a table update, data is changed within the data-block (assuming there is sufficient space in the block for this change to take place). However in an index, when a key is changed, it’s position within the tree has to change. Remember, a key has one and only one position within a B-Tree. So when it changes, the old entry has to be deleted and a new one has to be created at a new leaf. Chances are, the old entry may never be re-used. Because Oracle would reuse a key-entry slot only when the newly inserted key is exactly the same as an old (deleted) one, including data-type, length and case. And what are the chances of that happening ? Most applications at my client-sites use a sequence to generate NUMBER keys (especially primary keys). Unless they are using the RECYCLE option, the sequences do not generate the same number twice. So, the deleted space within the index remains unused. This is the reason why during large-scale DELETEs and UPDATEs, the table-size Paper #135 / Page 5 shrinks or at least remains constant, whereas the indexes grow continuously. From the above explanation of B-Trees, the following dos and don’ts emerge : · Avoid indexing columns, that are subject to high UPDATEs. · Avoid indexing multiple columns in tables, that are subject to high DELETEs. If possible, only index the primary-key and/or column(s) determining the deletes on such tables. If indexing multiple columns is unavoidable, then consider partitioning the tables based on those columns and do a TRUNCATE on each such partition (instead of a DELETE). TRUNCATE simulates a drop and re-create of the table and index by re-setting the high-water mark, when used with the DROP STORAGE clause. · Avoid creating b-tree indexes for columns with low selectivity (less uniqueness). Low selectivity leads to dense leaf-blocks, causing large-scale index scans. The higher the uniqueness, the better the performance, since range-scans would reduce and maybe even be replaced with an unique scan. · Null values are never stored in single-column indexes,. In the case of multi-column indexes, the value is stored only if one of the columns is not null. Bear this in mind while constructing IS NULL or IS NOT NULL clauses for DML statements. An IS NULL would never induce an index-scan, whereas an unrestrained IS NOT NULL would cause a full index range-scan. You have heard these advises before, but now the precise logic behind these words of wisdom is apparent. The importance of PCTFREE For a B-Tree index, PCTFREE determines the extent of a leaf-split. In other words, PCTFREE indicates the amount of free-space within a block for “future updates”. However in the case of an index (unlike a table), these updates do not make sense, since an update anyway forces a delete and subsequent insert. In the case of indexes, PCTFREE plays a role mostly at the time of index-creation. A non-zero value specifies the block-splitting ratio. If PCTFREE is set to 20, during index-creation, upto 80% of the leaf may contain key-information. However the remaining 20% should be available for future inserts of key-information into that leaf-block. This ensures that during run-time inserts, there is minimal overhead in terms of incurring leaf-block splits. Even though a higher PCTFREE may cause index-creation time to increase, it prevents the performance-hit from being deferred to actual usage time. So, the end-user, who is waiting for a row to be inserted does not incur the performance penalty associated with a leaf-block split.
  • 6. Based on this information, the following points emerge : · PCTFREE for an index is used primarily during creation. It is ignored during actual usage. · Specify a higher PCTFREE for OLTP applications, if the table is a popular one, incurring a lot of DML Paper #135 / Page 6 changes (via interactive user-screens); · Specify a lower PCTFREE, if the index-creation time is critical. This will pack in more rows per leaf-block, thereby avoiding the need for further splitting at creation-time. This is of paramount significance to shops, that have “24x7” availability requirements. Index-creation in most cases, requires considerable downtime (especially if the table is a multi-million row table). Lesser the amount of index-creation time, smaller can be the maintenance-window. I have seen this tiny, often unnoticed parameter save around 20% of index-creation time. At a high-availability site, an index on a table containing around 11 million rows took me about 80 minutes to build using PCTFREE of 30 and a parallel degree of 4. The same index on the same table, with 13.5 million rows took me around 90 minutes to create with a PCTFREE of 0 (without any hardware/software enhancements). Nologging (minimal redo) was on during both creations. · For any column where the values are constantly increasing, it is probably a good idea to set a very low PCTFREE (even, zero). This is because only the rightmost leaf-block will always be inserted into. This will make the tree grow towards the right. The leftmost leaves would remain static. So, there is no sense in leaving any part of those blocks empty with a non-zero PCTFREE. Partitioned indexes Partitioned indexes are indexes, which have been horizontally sub-divided based on a specific range of key-values. Partitioning allows logically dependent structures to be physically independent. This allows maintenance operations to be performed on specific partition, while the others are still available for access. Thus, a specific partition may be offline and unavailable, while the other partitions are online and available for access. An index-partition may be re-built or recovered with minimal effect on applications. Each index-partition may have different storage characteristics and may be created in different tablespaces. Partitioned indexes may be created even for non-partitioned tables. Partitioned index-related terms Global and Local indexes : When an index is partitioned in a similar fashion as the table, in terms of ranges of partition-keys, then it is referred to as a local index. In other words, the local index shares the key-ranges with the parent table. It would store the keys of only it’s corresponding table-partition. A global index does not have a one-to- one correspondence with any table-partition in terms of partition-key ranges. A global index would store rows from multiple table-partitions. A local index is also referred to as an equi-partitioned index; whereas a global index is also referred to as a non equi-partitioned index. For example, a table may be partitioned into 52 segments based on the week-of-year. However, the index might be partitioned into 12 segments based on month-of-year. Such an index would be termed a global index. If the index were partitioned into 52 segments, it would be referred to as a local index. A bit-mapped index on a partitioned table has to be a local index.
  • 7. Prefixed and non-prefixed indexes : When an index of a partitioned table contains the partition key as the leading column, it is termed as a prefixed index. A non-prefixed index does not have partition key columns as the leading keys. Local pre-fixed indexes should be created, whenever possible. Since they have a one-to-one correspondence with the partitioned table, administration is easier. Global pre-fixed indexes theoretically may have a slight performance edge at times, since the overhead of accessing large number of indexes is avoided. However partition pruning (where the partition key-value specified in the WHERE clause helps Oracle in determining which partition might contain the required results and accesses only that partition) helps in super-charging local partition access. Even in situations where partition pruning is not possible, parallel access of multiple local indexes via PQO may provide higher performance. It is generally more expensive to scan a non-prefixed index, compared to a pre-fixed index, since as mentioned earlier, in the case of a pre-fixed index, the optimizer can use the partition key-value to scan just the necessary index partitions (rather than all) for a predicate referring to the indexed columns. Oracle8.x does not support global non-prefixed indexes, since they do not have any practical utility. A global index may be split into local indexes or multiple local indexes may be merged into a global one. Considering partitioned indexes Let me illustrate this “partitioning scenario” with an example. One of my clients is a company providing free e-mail via the web. Their users receive a lot of e-mails. When a user deletes a message, the mail-entry is “deleted” from the main-messages table and moved to a garbage-bin. This is achieved by setting the garbage-flag to ‘1’ for that row in the main table. Only when the user specifically deletes it from his garbage-bin, the mail is permanently deleted. Many users set up their account such that once a week, their garbage-bin is automatically purged. So every week-end, this huge batch-job was run to delete all rows from the main-table where the garbage-flag = ‘1’. Since the garbage-flag column was being used in the WHERE clause of the DELETE, it was part of a regular B-Tree index (a bit-mapped index was not used even though the cardinality was low, because the column was subject to high updates and another key column was being used as the index-prefix). However, every time it was updated to ‘1’, it’s index-entry would be deleted and a new-one would be created. Furthermore, when the record would finally be deleted, the index-entry would continue to take up space. Thus the table would not significantly grow in size (due to e-mails being deleted and inserted all the time). However the index was growing at an incredible rate, taking up large amounts of tablespace area. Finally this problem was solved by replacing the design with a “partition-aware” design. Consider partitioning indexes : · for intense OLTP applications, dealing with a large number of rows. The flexibility in administrating Paper #135 / Page 7 relatively small segments is a great boon. · for high-availability (24x7) environments, where the down-time associated with an index-rebuild cannot be tolerated · for better overall performance. Whenever possible, Oracle8/8i parallelizes scans of partitioned indexes. Also partition elimination allows specific partitions to be eliminated from searches based on the key-ranges. This vastly expedites index-scans. Finally, partitioning allows an index to be spread out over multiple physical tablespaces/data-files, thereby reducing the occurrence of I/O hot-spots.
  • 8. Do not partition indexes on key-values prone to constant updates, especially if such updates cause partition migration, where a row has to be moved from one partition to another. Lastly, one frequently question that pops up at client-sites is, how many partitions can be realistically created without any performance degradation ? Theory apart (where thousands and thousands of partitions can be created), the answer to this question depends on various factors such as system resources (CPUs, memory, I/O channels across which the partitions are created, etc.) and varies from site to site. A lot also depends on applications and data. If the data lends itself to a “clean” partitioning structure, based on a popular (frequently used in most queries) key-column(s), then partitioning across a large number of partitions would be more effective, since partition pruning is possible in most situations. However if such a popular key column is not available, then utilizing a large number of partitions may cause performance degradation, since multiple partitions would need to be frequently visited to retrieve the required values. As such, it is always essential to ensure that you select a popular key column as the partitioning key. If such a column does not currently exist, evaluate introducing it explicitly (for instance, by denormalizing the table). Additionally, always ensure that there is sufficient scope for parallelizing partitioned operations (such as multiple CPUs, data spread across multiple disks/controllers, etc.). I have seen partitioning to be very effective in certain situations, when the number of partitions do not exceed a few hundreds. After that, the law of diminishing returns comes into play, as system resources get saturated and performance begins to stink. Reverse-key indexes A reverse-key index is primarily a b-tree index, where the bytes of key-values are stored in a reversed order. By reversing the keys, index entries are spread more evenly throughout the b-tree. This is very useful in an OPS (Oracle Parallel Server) environment, where contention for the same leaf-blocks might cause inter-instance “pinging” to occur, thereby affecting performance adversely due to excessive disk I/O. Paper #135 / Page 8 Examples of a reversed key are as follows : ADAMSON NOSMADA 1558 8551 Dates in a reverse-key index are stored by reversing the seven bytes contained in a DATE data-type. Considering reverse-key indexes In late 1996, at a client-site in Bombay, India, our team was implementing a Custodial Services system. We faced a major performance-impediment with the share-certificates table; especially when the clients would acquire a large number of share-certificates with sequential numbering. We had created the right index on the table and had ensured that the index was indeed, being used. However, even a pure index-access would take unusually long : at least 15 seconds more than what we expected (based on our experiments with other similar tables). Finally we figured out that storing those sequential certificate numbers caused the index to be lop-sided. In other words, some of the leaves would be dense (heavily populated), whereas some of them would be sparse, based on the
  • 9. series of share-certificates we obtained. Most DML activity would focus on these dense leaves, thereby creating “hot-spots” on the index. By hot-spots, I mean index-activity would be much more for these few leaf-blocks, compared to the others. Since there would usually be only one disk-controller accessing those blocks, all activity would have to be serialized, thereby adversely affecting response-time and throughput. In such a situation, reverse-key indexes would have been a boon. However we were using Oracle7 v7.3 at that time, where the feature was still not available. We lived with the situation for a while. Finally, we circumvented the situation by reversing the values within the application. We had two columns in the table, a column that would store the share-certificate number as it was and a primary-key column, which would store the same share-certificate in a reversed order. We wrote a stored function, which would accept the actual share-certificate as an input parameter and return the reversed number, which would subsequently be inserted in the table as the primary key. This gave us a relatively “well-balanced” index. The same concept applies to any value that increases in spurts : sequential numbers, date and time columns, etc. Increasing in spurts indicates a scenario where the value monotonously increases, then there is not much activity for a while, thereby creating “gaps” in the values; then the value constantly increases again. Such columns would be prime candidates for using the Oracle8/8i reverse-key indexes. Also, in fast-growing tables where indexes are built on sequential values (such as a primary-key index), and large-scale deletes frequently occur, the index may begin to “slide”. A sliding index is one that continuously grows towards the right (newer rows being inserted), while the left-portion is constantly being deleted (older rows being purged). The left-portions of the tree comprises of nulls or empty leaf-nodes, whereas the tree is expanding to the right, thus appearing to “slide”. Reversing the index may halt the right-oriented growth (due to constantly increasing key-values) and make the growth more balanced by placing the reversed key-values in all directions (left and right). Additionally, partitioning the index (on a “rolling window” scheme) and truncating older partitions (rather than deleting) would help in eliminating the large number of empty leaf-blocks. One question might come to your mind : how did we manage to figure out that our index was indeed lop-sided ? We used an “ALTER SESSION SET EVENTS” command to understand the index-structure better. This command is mentioned in more detail in Appendix A. Some caveats to bear in mind while using reverse-key indexes : · Reverse key indexes are not effective when used in range scans · Reverse key indexes are prone to all the restrictions of regular b-tree indexes, such as avoiding excessive Paper #135 / Page 9 DML activity, periodic re-building, etc. (since they are merely a variation of B-Trees). Index-organized tables (IOTs) Index-organized tables are tables, where the rows are stored in a B-Tree structure, based on the primary-key value. A primary key definition is mandatory for an IOT. In Oracle8 v8.0.x, IOTs do not have rowids (this restriction is removed in 8i via “logical rowids” [explained below]). An index entry is expected to be terse to remain effective. Since a full-fledged row may be too big to retain index-effectiveness, Oracle8/8i provides the PCTTHRESHOLD clause to indicate a percentage of the total block-size. All non-primary key columns that cause a row to grow beyond the size of this percentage are moved to an “overflow” tablespace.
  • 10. Considering index-organized tables A short while ago, I was part of a team, building a large data-warehouse for a major investment company in Oracle8/8i. In the data-warehouse, we had a bunch of code-tables, acting as dimension tables. In the first iteration of the physical design, we built all those code-tables as regular tables with two columns : the code-id and the description. We had a primary key index on the code-id. We also cached some of these tables and their indexes in the Oracle SGA. However with more familiarity with Oracle8i, we observed that these code-tables were prime candidates for using the index-organized feature. Since there was only one index on each of these tables, we could use the primary-key to structure the rows in these tables in a B-Tree format. In the second iteration of the physical design, we re-defined most of our code-tables as index-organized tables. This change brought us space-savings to the tune of 35%. From around 800 MB for both regular-tables and the primary key indexes, the space-usage has dropped down to approximately 520 MB for the index-organized tables. These space-savings affect not only disk-usage, but also memory usage (since many of the tables were cached). That was true space-savings for us, since memory is always at a premium! Soon after we could consider caching additional information within the SGA, without having to expand it. Needless to add, this space-saving was obtained due to absence of the physical rowids and any indexes on the index-organized tables. This example illustrates that tables such as code-tables or certain master tables, not prone to frequent changes are ideal for using the index-organized feature of Oracle8/8i. This useful option brings substantial space-savings to the table, especially when going from a regular table with an index comprising of most of the columns in the table (built that way to exploit the “index-only lookup” access-path) to an index-organized Paper #135 / Page 10 table. Some caveats with IOTs in Oracle8 versions (prior to 8i): · The table structure cannot be altered · Non-primary key indexes cannot be created · Absence of rowids might cause problems while migrating Oracle7 applications to Oracle8, if the application DML explicitly depends on rowids Note that all the above restrictions have been eliminated in Oracle8i, allowing IOT usage to be more practical. The new “logical rowids” contain the primary key of the referenced row, instead of a physical location within the database. This means that if a row is moved to a new location, the logical rowid would still contain a valid reference to the row and would not need to be updated. To retain the speed of conventional rowids, logical rowids also contain a physical location hint, which can be used to optimize performance. If an index is created on a field other than the primary key (note that IOTs support secondary indexes in 8i), Oracle8i will create a logical index using logical rowids to reference the table rows. One caveat that does remain even in 8i is row-chaining, which is inevitable with large-sized rows.
  • 11. Bit-mapped indexes The biggest difference between a b-tree index and a bit-mapped index is that the former encourages indexing on columns with high selectivity, whereas the latter encourages low selectivity. This is primarily due to inherent structural differences. A bit-mapped index creates a binary bit-map stream, consisting of 1s and 0s for every distinct key-value. It uses distinct bits (of every byte) to create these binary steams. Due to application of bit-level binary arithmetic, large-numbers of rows can be processed at high speeds. Also, if a table has multiple low-cardinality columns, then bit-map indexes may be created on each of those columns. Multiple indexes in turn will be merged using bit-level boolean logic resulting in very fast index-access times. In the case of compound indexes, a bit-mapped index can have upto a maximum of 14 columns in Oracle7.x and upto 30 columns in Oracle8/8i (always 2 less than B*Tree indexes). Bit-mapped indexes are available only with CBO. Bit-mapped indexes are stored in compressed form, thereby causing huge space-savings. Oracle uses a proprietary compression algorithm, capable of handling even high-cardinality columns (this is useful in scenarios such as a star-schema, where the dimension tables have very high cardinality). On a data-warehouse at a client-site, a B-tree index on a column with 2 distinct values on a table with 12 million rows took up around 184Mb, whereas a bit-mapped index on the same column now takes up a mere 3Mb – a direct saving of more than 98% disk-space! The star-transformation access-path (introduced in Oracle8) uses bit-mapped indexes to merge results from multiple dimension tables with a large fact table to produce extremely fast query results, without having to perform an expensive Cartesian product as in a regular star query. An example of a good candidate for a bit-mapped index would be the “marital status” column on the customer table in a data-mart for the Sales department. The marital status column would have a domain consisting of the following 4 values : single, married, divorced, widowed. The logical view of a bit-mapped index created on this column is represented in table 2a : Paper #135 / Page 11 'RPDLQ 9DOXH &XVWRPHU /DVW 1DPH 6LQJOH 0DUULHG 'LYRUFHG :LGRZHG %LWPDS SDWWHUQ 6PLWK :KLWH %URZQ %ODFN Table 2a : column “Bit-map pattern” provides the logical index-key pattern [remember a bit may either be on (1) or off (0) ] From a physical standpoint, each bit-map stream consists of a header portion and a body, wherein the header comprises of the key-value and the beginning and ending rowids for a range of rows having that key-value. The body comprises of the actual bit-map stream for the same range of rows. The size of the body is guaranteed to be 50% or less of the initialization parameter DB_BLOCK_SIZE. Thus, a bitmap may be stored as smaller pieces to adhere to this rule. The physical structure is depicted in figure 2b.
  • 12. Paper #135 / Page 12 Header body {Key-value} {begin ROWID} {end ROWID} {bit-map stream} In Oracle7 : Key-value Begin ROWID End ROWID Bit-map stream ‘Salaried’ 12345211.3415.5642 12345211.3415.5822 0101010000111 In Oracle8/8i : Key-value Begin ROWID End ROWID Bit-map stream ‘Salaried’ AAAAgmAADAAAAE8AAB AAAAgoAADAAAAFVAAC 01110111011 Figure 2b: Physical view of a bit-mapped index A few things to consider while creating a bit-map index : · Is the table often queried by this column ? If not, is an index really needed on the column ? · How many rows are present in the table ? A small table (a few thousand rows) does not warrant a bit-mapped index. · Does the column have low cardinality ? If not, is the degree of uniqueness high ? Degree of uniqueness may be depicted as “number of unique values / total number of rows in the table * 100”. · Is the column prone to frequent DML (non-batch, OLTP DML) ? If so, it’s probably a good idea to leave it alone or maybe use it as a secondary column to create a regular B-tree index (the leading column should have high selectivity). · Are there multiple columns in the table, which are good candidates for bit-mapped indexes ? If so, would such columns be frequently referred in the WHERE clause of queries ? If so, there are high chances of the bit-mapped indexes on these columns being merged by CBO to provide high query throughput. · Is the data in the table subject to frequent changes simultaneously by multiple users ? If so, a bit-mapped index may not be convenient. Bit-mapped indexes restrict concurrency, due to the entire bit-map being locked during a single DML operation affecting any row in the range of rows represented by the bit-map. This could potentially cause hundreds of rows to be locked by a single DML statement, intending to affect a single row. This is not an issue during parallel DML operations affecting partitioned tables, since index-maintenance during such parallel DML occurs at the partition-level. As such, a single index partition is not subjected to parallelism, thus leading to concurrency problems. Function-based indexing This new feature introduced in Oracle8i allows functions to be indexed and used in SQL statements. Earlier Oracle releases expressly disabled index-usage when functions were utilized on the key column. However now, SQL or user-defined functions can be indexed. For instance, a query such as the following would benefit tremendously from function-based indexes : SQL SELECT * FROM names WHERE INITCAP(name) LIKE ‘Bill%’;
  • 13. Paper #135 / Page 13 An index can be created on a function as follows : CREATE SQL INDEX upper_nm_idx01 ON names(INITCAP(name)) TABLESPACE tblspc_nm STORAGE(storage_clause); Now, applications can issue case-insensitive queries such as the following : SQL SELECT * FROM name WHERE name LIKE ‘Bill%’; Function-based indexes are also physically stored in a B-tree structure. Please refer to the Oracle8i documentation (Oracle8i Concepts) set for further explanation of function-based indexing. Application domain indexes Application domain indexes are “extended” indexes specific to a certain application domain. These are indexes created on non-conventional data-types (domains) such as spatial data and multimedia data-types such as images and audio/video streams, spreadsheets and documents, etc. Here, an encapsulated set of code-routines referred to as an indextype define the index access and implementation rules for efficient and speedy retrieval of complex domains. A data-cartridge is custom-built (via the Oracle8i Data-cartridge Interface) to define the application that controls the domain and also defines the inherent structure of the domain index. In other words, all operations performed on the index such as range scans, equality checks, etc. need to be explicitly defined. The index can be stored inside the database as an index-organized table or externally, as a file. As of Oracle8i v8.1.5, a domain index can have only a single column. This column can be a regular scalar data-type or a user-defined attribute of an object or a LOB. Information on domain indexes (meta-data) cannot be found in conventional index-related views such as DBA_INDEXES, USER_INDEXES, etc. The data-cartridge needs to utilize a specific index meta-data management strategy and nominate a pre-defined table to hold the meta-data on domain indexes of a certain indextype. Furthermore, wrapper views can be created on top of the meta-data table, if necessary, for additional encapsulation. The Oracle8i documentation set (Oracle8i Data Cartridge Developer's Guide) discusses application domain indexes in detail. Abstract Data-types their Indexes Peek into your abstract data-types with a magnifying glass to identify the scalar data-types, which need indexing. Once the abstract type has been broken down into scalars, all the above mentioned indexing rules apply to them. Whenever possible, ensure that all your DML specifies the absolute path to these scalar types (else the optimizer may not use the right index). By absolute path, I mean “person.name.last_name” and not just “person” even “person.name”. Considering an index-rebuild This is the million-dollar question that many DBAs and developers face : when should one think about re-building an application’s indexes ? I have noted that in some organizations, there is a fixed schedule : every 3 months, indexes are re-created on tables, undergoing major DML activity. However some of these frequent index-rebuilds might be unnecessary or even indexes of less frequently used tables might need to be re-built on a more regular
  • 14. basis. How does one determine whether they need to be re-built or not ? How does one get actual numbers indicating that an index is a candidate for re-building ? By using the command ANALYZE INDEX…VALIDATE STRUCTURE. There is another old command called VALIDATE INDEX. This is still available in Oracle8/8i (mainly for backward compatibility). Either of these commands populate the INDEX_STATS view with meaningful information, that helps in determining whether an index should be re-built or not. Please refer to figure 3a for a description of the structure of INDEX_STATS view. As is apparent from the structure, DBAs and developers can use the INDEX_STATS view to glean some useful information. The statistics in INDEX_STATS are different from the ones in DBA_INDEXES. The statistics in DBA_INDEXES are created as a result of using the COMPUTE STATISTICS or ESTIMATE STATISTICS options of the ANALYZE command and are used by the cost-based optimizer (CBO). The statistics in INDEX_STATS are created by the VALIDATE STRUCTURE option of the ANALYZE command. Another important difference is that the ANALYZE STRUCTURE…DELETE STATISTICS command erases statistics in DBA_INDEXES; however the statistics in INDEX_STATS are not erased. They get erased only when the index is dropped or get re-computed every time the ANALYZE…VALIDATE STRUCTURE command is run. The INDEX_STATS view only contains information about one index at any given point in time. Don’t worry about old statistics in the INDEX_STATS misleading CBO. CBO does not use the statistics in INDEX_STATS. Paper #135 / Page 14 SQL desc sys.index_stats Name Null? Type My comments ------------------------------- -------- ---- -------------- HEIGHT NUMBER Height of tree BLOCKS NUMBER NAME VARCHAR2(30) PARTITION_NAME VARCHAR2(30) LF_ROWS NUMBER Leaf rows LF_BLKS NUMBER Leaf blocks LF_ROWS_LEN NUMBER LF_BLK_LEN NUMBER BR_ROWS NUMBER Branch rows BR_BLKS NUMBER Branch blocks BR_ROWS_LEN NUMBER BR_BLK_LEN NUMBER DEL_LF_ROWS NUMBER Deleted leaves DEL_LF_ROWS_LEN NUMBER DISTINCT_KEYS NUMBER MOST_REPEATED_KEY NUMBER BTREE_SPACE NUMBER USED_SPACE NUMBER PCT_USED NUMBER ROWS_PER_KEY NUMBER = 1 for UNIQUE keys BLKS_GETS_PER_ACCESS NUMBER Figure 3a : description of the INDEX_STATS view in an Oracle8/8i database
  • 15. Paper #135 / Page 15 COLUMN name FORMAT a25 -- increase if your index-names are 25 chars COLUMN “Total leaf rows” FORMAT 999,999,999,999 COLUMN “Deleted leaf rows” FORMAT 999,999,999,999 SELECT name, lf_rows “Total leaf rows”, del_lf_rows “Deleted leaf rows” FROM SYS.index_stats WHERE name = UPPER(‘enter_index_name’); Figure 3b : Query to determine whether index is to be re-built (to be run after ANALYZE INDEX…VALIDATE STRUCTURE as a DBA user) The query listed in figure 3b provides the total leaf rows and the deleted leaf rows for a given index. If the deleted leaf rows seem relatively high compared to the total leaf rows, then the index should be re-built. I use 20% as a general rule-of-thumb. If the deleted leaf rows are 20% or more of the total leaf rows, I rebuild the index (provided Management waves the green flag!). Also , the command provided in appendix A (ALTER SESSION SET EVENTS…) provides additional information to help in deciding whether an index should be rebuilt. The REBUILD option Starting with Oracle7 7.3, you can use the REBUILD option of the ALTER INDEX command to rebuild indexes. You can even use this option to reverse a regular B-Tree index and vice-versa. However a caveat with REBUILD is, it does not detect and eliminate index corruption, since it bases the rebuild on the existing index (which might be corrupt already). (This holds true even in Oracle8i.) ANALYZE TABLE …VALIDATE STRUCTURE CASCADE is the best mechanism to detect index-corruption. This command matches each row in the table against all indexes and each row in every index against the table. If there is any corruption found, an error message is returned. Subsequently the index may be dropped and re-built using the regular DROP and CREATE INDEX commands, rather than the REBUILD option of the ALTER INDEX command. Conclusion By selecting an approach that considers the tips outlined in this paper, you can not only determine when to rebuild an index, but also how should the new index be re-built – as a reverse-key index or as a partitioned index or even converting a table to an index-organized table. Even though Oracle8i has vastly increased the number of indexing options available, B-Tree indexes continue to offer the best solution in most cases. As long as they are well-maintained, they provide acceptable performance under diverse conditions. However, certain situations, explained above, prove to be ideal for deviating from the B-Tree approach and instead using another index type such as bit-mapped, or even variations of the B-Tree such as reverse-key, function-based, partitioned or index-organized tables. With the versatile index offerings of Oracle8i, there has never been a better time to put on that new thinking cap and look at the process of indexing as an art, not a science!
  • 16. Paper #135 / Page 16 Appendix A Command to dump an index tree structure The command “ALTER SESSION SET EVENTS ‘IMMEDIATE TRACE NAME TREEDUMP LEVEL level_number’;” dumps the structure of an index b-tree. It gives useful information such as number of levels in the index and number of rows per level. Such information helps the DBA to decide whether an index needs to be re-built and if so, whether it should be reversed. The level_number mentioned in the command above needs to be replaced with an actual number. In Oracle8/8i, this level-number is the “object_id” of the index in SYS.DBA_OBJECTS. Running the command gives a trace-file in the “user_dump_dest” directory. The trace-file name usually is of the form : “ora_SID_NAME_PID#.trc” , where SID_NAME is the ORACLE_SID and PID# is the process-id number. Immediately after running this command, you can go to the user_dump_dest directory and run the following command : “ls –lt” to pick up the latest trace file. A sample trace-file is provided in fig. 4a. The last lines of the dump-file contain the meat of the output (between “begin tree dump” and “end tree dump”). The trace file size is directly proportional to the size of the index. The file-contents can be interpreted by looking at the number of levels : the branches and the leaves per branch. In the sample file provided in fig. 4a, there is only one branch (0x40002b) and 4 leaves (0x4003f0, 0x4003f1, 0x400b0f and 0x400b10), since the dump was produced for a small index with just 1,819 rows. The rows contained in each leaf are 503, 418, 498 and 400 respectively. This indicates that all the leaves are well-balanced (in terms of rows per leaf). So, it is a good idea to leave this index alone. However if the rows in some leaves seem excessively high compared to other leaves, then probably those leaves are hot-spots and could lead to I/O bottlenecks. Generally, spurts of sequential values or large delete-jobs cause such uneven distribution of keys. If the culprit is merely a huge batch delete job, then probably the situation can be set right by partitioning the table and truncating the partition. If partitioning is a not a feasible solution, then re-building the index (without reversing) after such batch-deletes would help. Alternatively, if the imbalance is caused by spurts of sequential values being inserted in the table, then reversing the key(s) would help.
  • 17. Paper #135 / Page 17 Dump file /opt/app/oracle/admin/dv01/udump/ora_dv01_4231.trc Oracle8 Enterprise Edition Release 8.1.5.0.0 – Production PL/SQL Release 8.1.5.0.0 – Production ORACLE_HOME = /opt/app/oracle/product/8.1.5 System name: sample Node name: sample Release: 4.0 Version: 3.0 Machine: 3446A Instance name: dv01 Redo thread mounted by this instance: 1 Oracle process number: 7 Unix process pid: 4231, image: oracledv01 Wed Jul 14 11:52:11 1999 *** SESSION ID:(8.69) 1999.07.14.11.52.11.000 ----- begin tree dump branch: 0x40002b 4194347 (0: nrow: 4, level: 1) leaf: 0x4003f0 4195312 (-1: nrow: 503 rrow: 503) leaf: 0x4003f1 4195313 (0: nrow: 418 rrow: 417) leaf: 0x400b0f 4197135 (1: nrow: 498 rrow: 498) leaf: 0x400b10 4197136 (2: nrow: 400 rrow: 400) ----- end tree dump Figure 4a : Sample trace-file (output of the ALTER SESSION…SET EVENTS command described in appendix A) Warning : Please use all commands and scripts provided in this paper at your own risk. I have used all the commands, provided herein, multiple times on Oracle8 v8.0.x and v8.1.x databases without any kind of adverse effect. However neither I nor my company, Immedient (formerly Raymond James Consulting), warrant that this document is error-free and/or assume any risk associated with it’s usage . Please test all scripts and commands on a development database prior to usage on a production database. References · Oracle8i Server Documentation · Oracle 24x7 Tips and Techniques; Venkat S. Devraj; Oracle Press (Osborne/McGraw-Hill); 1999