For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

  1. Composite Index (Recommended)

    • This will help optimize queries filtering by cif and request_timestamp together.

  2. 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

  1. Most Selective Column First

    • If cif has high cardinality (many unique values), placing it first makes sense.

    • If request_timestamp is more selective (e.g., filtering for a small date range retrieves fewer rows), it might be better as the leading column.

  2. Query Usage Pattern

    • Your query filters on cif and request_timestamp, so (cif, request_timestamp) is a good choice.

    • If you frequently query by request_timestamp alone, the index should be (request_timestamp, cif) for better efficiency.

  3. Index Range Scan Efficiency

    • (cif, request_timestamp): Optimized for queries that start with cif in the WHERE clause`.

    • (request_timestamp, cif): Better for queries primarily filtering by request_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:

  1. Index on parent_id only

  2. Composite index on (parent_id, is_deleted)

Index on parent_id Only

Pros:

  • Helps efficiently filter rows by parent_id.

  • If parent_id has high selectivity (few matching rows), Oracle can quickly fetch the relevant rows.

Cons:

  • is_deleted filtering still requires a table scan or post-filtering step.

  • If parent_id returns a large number of rows, Oracle must still filter is_deleted separately, making the query slower.

Best suited when:

  • parent_id alone is highly selective (e.g., fetching a few rows).

  • is_deleted is not used often in queries.

Composite Index on (parent_id, is_deleted)

Pros:

  • Oracle can filter on both parent_id and is_deleted directly in an INDEX RANGE SCAN, avoiding unnecessary table scans.

  • If parent_id fetches many rows, is_deleted filtering is optimized at the index level.

  • Covers both existing and future queries filtering parent_id and is_deleted.

Cons:

  • Slightly larger index size compared to a single-column index.

Best suited when:

  • Queries frequently filter on both parent_id and is_deleted.

  • parent_id retrieves many rows, and is_deleted helps 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_id

  • The filter condition userattrib1_.value = '1311310003'

Recommended Indexes

  1. Index on user_attribute.user_id (helps JOIN performance)

  2. Index on user_attribute.value (helps WHERE condition)

  3. Composite Index on (value, user_id)

    • This helps the WHERE clause first, then efficiently fetches user_id.

  4. Ensure user_entity.id is the PRIMARY KEY

    • If 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 WHERE conditions suggest that the following composite index could be beneficial:

    Why?

    • The index covers all filtering conditions, improving lookup efficiency.

    • Including ecase_key in the index helps with the DISTINCT count.

  • If ecase_key is already unique, we may only need:

    • This ensures efficient filtering, and DISTINCT will have fewer rows to process.

Query 7

  • The JOIN condition is on schema_id and schema_version, so this helps in lookups.

Suggested Indexes

Composite Index on FLW_CASE

Create an index covering the WHERE clause conditions:

Why?

  • archived is a filtering condition (= 0), which makes it a good leading column.

  • created_date has a range condition (> TO_TIMESTAMP(...)), so it should be next.

  • case_definition_schema_id and case_definition_schema_version help with the join.

Index on FLW_CASE_DEF

To speed up the JOIN, create an index on FLW_CASE_DEF:

Why?

  • The JOIN condition is on schema_id and schema_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

Create a composite index covering the WHERE clause conditions:

Why?

  • earchived and epreliminary are filtering conditions (= 0), so they should be leading columns.

  • ecreated_date has a range filter (> TO_TIMESTAMP(...)), making it the next best column.

  • ecase_definition_schema_id and ecase_definition_schema_version help with lookups.

Index on EFLOW_CASE_STATUS

Create an index on eflow_case_status to speed up the JOIN:

Why?

  • ecase_key is used in the JOIN condition.

  • estatus_name = 'status' is highly selective, making it a good column to include.

  • estatus_value is 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_date is 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

  • The 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 on party0_.name, party0_.alias, and accounts1_ 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