Index Suggestions by Query
About
This page is designed to help developers, DBAs, and data engineers analyze SQL queries and determine the most effective indexing strategies for performance optimization. It provides practical guidance on what types of indexes should be created based on the structure of a query, the WHERE clause, JOINs, ORDER BY, and GROUP BY conditions.
Query 1
SELECT
d.device_id AS device_id,
du.device_id AS user_device_id,
d.created_date_time AS device_created_time,
du.login_date_time AS user_login_time,
du.user_id AS user_id
FROM
device d
LEFT OUTER JOIN device_user du ON d.device_id = du.device_id
WHERE
d.user_id = ?
ORDER BY
du.login_date_time DESC NULLS LAST;On device table
a. Index on user_id column
Reason: Helps with the WHERE d.user_id = ? condition.
b. Composite index on user_id and device_id (optional)
Reason: Helps with both filtering and joining to device_user.
On device_user table
a. Index on device_id column
Reason: Improves performance of the join ON d.device_id = du.device_id.
b. Composite index on device_id and login_date_time
Reason: Helps both the join and the ORDER BY du.login_date_time DESC
Query 2
To optimize this query in Oracle, we should create indexes on the columns used in the WHERE clause to improve the performance of the filtering conditions.
Suggested Indexes:
Composite Index (Recommended)
This will help optimize queries filtering by
cifandrequest_timestamptogether.
Alternative: Individual Indexes (If composite index is not possible)
The optimizer may use both indexes for filtering, but a composite index is usually more efficient.
Does this order matters (cif, request_timestamp) ?
Yes, the order of columns in a composite index matters because Oracle stores and searches the index in the order the columns are defined. The order impacts how the index is used in queries.
Choosing the Right Order
Most Selective Column First
If
cifhas high cardinality (many unique values), placing it first makes sense.If
request_timestampis more selective (e.g., filtering for a small date range retrieves fewer rows), it might be better as the leading column.
Query Usage Pattern
Your query filters on
cifandrequest_timestamp, so(cif, request_timestamp)is a good choice.If you frequently query by
request_timestampalone, the index should be(request_timestamp, cif)for better efficiency.
Index Range Scan Efficiency
(cif, request_timestamp): Optimized for queries that start withcifin theWHEREclause`.(request_timestamp, cif): Better for queries primarily filtering byrequest_timestamp.
Query 3
Using NVL(someColumn, 0) = 1 in where clause
Using NVL(someColumn, 0) = 1 in a WHERE clause can negatively impact performance because it prevents Oracle from using an index on someColumn efficiently.
NVL(someColumn, 0)applies a function on the column, making Oracle evaluate it for every row.This disables index usage unless we have a function-based index.
Optimized Alternatives
1. Use someColumn IS NULL OR someColumn = 1 (If NULLs Exist)
Instead of:
Use:
Benefits:
Uses index on someColumn
Avoids function-based filtering
2. Create a Function-Based Index (If NVL is Unavoidable)
If NVL(someColumn, 0) is mandatory, create an index that includes the function:
Benefits:
Oracle can use the index even with NVL(someColumn, 0) = 1.
3. Store Defaults in the Table (Best for New Data)
If someColumn has many NULLs but should default to 0, consider:
Updating existing rows:
Enforcing a default at the schema level:
This way, you can safely use:
Query 4
Composite Index or Single Column Index in below query
We need to decide between:
Index on
parent_idonlyComposite index on (
parent_id,is_deleted)
Index on parent_id Only
parent_id OnlyPros:
Helps efficiently filter rows by
parent_id.If
parent_idhas high selectivity (few matching rows), Oracle can quickly fetch the relevant rows.
Cons:
is_deletedfiltering still requires a table scan or post-filtering step.If
parent_idreturns a large number of rows, Oracle must still filteris_deletedseparately, making the query slower.
Best suited when:
parent_idalone is highly selective (e.g., fetching a few rows).is_deletedis not used often in queries.
Composite Index on (parent_id, is_deleted)
parent_id, is_deleted)Pros:
Oracle can filter on both
parent_idandis_deleteddirectly in an INDEX RANGE SCAN, avoiding unnecessary table scans.If
parent_idfetches many rows,is_deletedfiltering is optimized at the index level.Covers both existing and future queries filtering
parent_idandis_deleted.
Cons:
Slightly larger index size compared to a single-column index.
Best suited when:
Queries frequently filter on both
parent_idandis_deleted.parent_idretrieves many rows, andis_deletedhelps narrow them down.
Which One Should we Choose?
Scenario
Best Index Choice
Query filters only parent_id
CREATE INDEX idx_rangement_parent (parent_id);
Query filters both parent_id and is_deleted frequently
CREATE INDEX idx_rangement_parent_deleted (parent_id, is_deleted);
parent_id retrieves many rows, but is_deleted significantly reduces them
Composite index (parent_id, is_deleted) is better
parent_id retrieves few rows (highly selective)
Index on just parent_id is sufficient
Query 5
Ensure Indexes on Join and Filter Conditions
The biggest performance bottlenecks are:
The JOIN on
userentity0_.id = userattrib1_.user_idThe filter condition
userattrib1_.value = '1311310003'
Recommended Indexes
Index on
user_attribute.user_id(helps JOIN performance)Index on
user_attribute.value(helps WHERE condition)Composite Index on (
value,user_id)This helps the WHERE clause first, then efficiently fetches
user_id.
Ensure
user_entity.idis the PRIMARY KEYIf it's not indexed already:
Query 6
Query is counting distinct case_key values based on several filtering conditions.
Ensure we Have the Right Indexes
The
WHEREconditions suggest that the following composite index could be beneficial:Why?
The index covers all filtering conditions, improving lookup efficiency.
Including
ecase_keyin the index helps with theDISTINCTcount.
If
ecase_keyis already unique, we may only need:This ensures efficient filtering, and
DISTINCTwill have fewer rows to process.
Query 7
The
JOINcondition is onschema_idandschema_version, so this helps in lookups.
Suggested Indexes
Composite Index on FLW_CASE
FLW_CASECreate an index covering the WHERE clause conditions:
Why?
archivedis a filtering condition (= 0), which makes it a good leading column.created_datehas a range condition (> TO_TIMESTAMP(...)), so it should be next.case_definition_schema_idandcase_definition_schema_versionhelp with the join.
Index on FLW_CASE_DEF
FLW_CASE_DEFTo speed up the JOIN, create an index on FLW_CASE_DEF:
Why?
The
JOINcondition is onschema_idandschema_version, so this helps in lookups.
Optimized Query
After creating indexes, rewrite the query to encourage INDEX RANGE SCAN:
Why Use a Hint (/*+ INDEX(...) */)?
Forces Oracle to use the index (
idx_flw_case_optimization), helping in query optimization
Query 8
Suggested Indexes
Composite Index on EFLOW_CASE
EFLOW_CASECreate a composite index covering the WHERE clause conditions:
Why?
earchivedandepreliminaryare filtering conditions (= 0), so they should be leading columns.ecreated_datehas a range filter (> TO_TIMESTAMP(...)), making it the next best column.ecase_definition_schema_idandecase_definition_schema_versionhelp with lookups.
Index on EFLOW_CASE_STATUS
EFLOW_CASE_STATUSCreate an index on eflow_case_status to speed up the JOIN:
Why?
ecase_keyis used in theJOINcondition.estatus_name = 'status'is highly selective, making it a good column to include.estatus_valueis being grouped, so including it avoids extra lookups.
Query 9
Suggested Index
Since we are filtering by ecreated_date, a good index to improve query performance is:
Why?
ecreated_dateis used in a range condition (< TO_TIMESTAMP(...)), so indexing it helps avoid full table scans.
Query 10
Issues Identified
1. Full Table Scans on USER_PARTY and USER_ACCOUNT_INFORMATION
USER_PARTY and USER_ACCOUNT_INFORMATIONThe optimizer is not using indexes, leading to slow performance.
This is likely because:
No indexes exist on the filtering columns.
The
LOWER()function prevents index usage onparty0_.name,party0_.alias, andaccounts1_columns.
2. OR Conditions Without Parentheses
(party0_.service_agreement_id = X AND party0_.access_context_scope = 0 OR party0_.legal_entity_id = Y AND party0_.access_context_scope = 0 OR party0_.bb_id = Z AND party0_.access_context_scope = 0 )This may be interpreted incorrectly. We should group conditions properly using parentheses.
3. LIKE Conditions on Large Columns
LOWER(column) LIKE '%value%'prevents index usage.If leading wildcards (
%value) are used, indexes cannot help.
Optimizations
1. Add Indexes for Better Performance
Index on Filtering Columns
Index on Searchable Columns (With Functional Index)
Since
LOWER(column)prevents index usage, create functional indexes:
If Oracle is not using the function-based indexes, a composite index might help, but it depends on how the optimizer processes our query. Before creating composite indexes, let's go through some key checks and options.
1. Verify Oracle is Aware of Function-Based Indexes
Run the following query to ensure the function-based indexes exist and are usable:
If the function-based indexes are not listed, Oracle is not recognizing them.
If the index status is UNUSABLE, rebuild them using:
2. Gather Statistics on Indexed Columns
Oracle may not use the indexes if table statistics are outdated. Run:
3. Consider Composite Index
If the optimizer still doesn't use function-based indexes, try a composite index covering frequently queried columns together.
Option 1: Composite Function-Based Index
Create a multi-column functional index on frequently filtered columns:
This is useful if multiple columns are always queried together.
If filtering only one column at a time, individual function-based indexes are better.
Last updated