[Solved] Optimize this query please

EverSQL Database Performance Knowledge Base

Optimize this query please

SELECT
      B.CE_ID,
      A.PPL_CNTR_ID,
      SUM ( A.NBR_IN ) ENTERS,
      SUM ( A.NBR_OUT ) EXITS,
      A.LOG_TS
      + DECODE ( TO_CHAR ( A.LOG_TS,
                       'mi' ),
               '05', 55
                    / 1440,
               '10', 50
                    / 1440,
               '15', 45
                    / 1440,
               '20', 40
                    / 1440,
               '25', 35
                    / 1440,
               '30', 30
                    / 1440,
               '35', 25
                    / 1440,
               '40', 20
                    / 1440,
               '45', 15
                    / 1440,
               '50', 10
                    / 1440,
               '55', 5
                    / 1440,
               0 )
          TS
FROM
      OUTPUTDB.TPPL_CNTR_TRAFFIC A,
      FLUX.V_CE_PPLCNTR B
WHERE
         A.LOG_TS BETWEEN '07-Sep-13' AND '08-Sep-13'
      AND A.PPL_CNTR_ID = B.PPL_CNTR_ID
      AND B.CE_ID IN (SELECT
                        DISTINCT CE_DPN_ID
                   FROM
                        TCE_RLT
                   START WITH
                        CE_PRN_ID = 5798
                   CONNECT BY
                        PRIOR CE_DPN_ID = CE_PRN_ID)
GROUP BY
      B.CE_ID,
      A.PPL_CNTR_ID,
      A.LOG_TS
      + DECODE ( TO_CHAR ( A.LOG_TS,
                       'mi' ),
               '05', 55
                    / 1440,
               '10', 50
                    / 1440,
               '15', 45
                    / 1440,
               '20', 40
                    / 1440,
               '25', 35
                    / 1440,
               '30', 30
                    / 1440,
               '35', 25
                    / 1440,
               '40', 20
                    / 1440,
               '45', 15
                    / 1440,
               '50', 10
                    / 1440,
               '55', 5
                    / 1440,
               0 )
ORDER BY
      B.CE_ID,
      A.PPL_CNTR_ID,
      A.LOG_TS
      + DECODE ( TO_CHAR ( A.LOG_TS,
                       'mi' ),
               '05', 55
                    / 1440,
               '10', 50
                    / 1440,
               '15', 45
                    / 1440,
               '20', 40
                    / 1440,
               '25', 35
                    / 1440,
               '30', 30
                    / 1440,
               '35', 25
                    / 1440,
               '40', 20
                    / 1440,
               '45', 15
                    / 1440,
               '50', 10
                    / 1440,
               '55', 5
                    / 1440,
               0 )

The inner subquery

                   SELECT
                        DISTINCT CE_DPN_ID
                   FROM
                        TCE_RLT
                   START WITH
                        CE_PRN_ID = 5798
                   CONNECT BY
                        PRIOR CE_DPN_ID = CE_PRN_ID

returns 970 rows , But it's taking very long time to execute , Please suggest any alternate clause or joining so that It runs faster . The 2 tables used have only one column in common , So I am pretty sure no cross joining is taking place .

How to optimize this SQL query?

The following recommendations will help you in your SQL tuning process.
You'll find 3 sections below:

  1. Description of the steps you can take to speed up the query.
  2. The optimal indexes for this query, which you can copy and create in your database.
  3. An automatically re-written query you can copy and execute in your database.
The optimization process and recommendations:
  1. Avoid Calling Functions With Indexed Columns (query line: 50): When a function is used directly on an indexed column, the database's optimizer won’t be able to use the index. For example, if the column `LOG_TS` is indexed, the index won’t be used as it’s wrapped with the function `DECODE`. If you can’t find an alternative condition that won’t use a function call, a possible solution is to store the required value in a new indexed column.
  2. Create Optimal Indexes (modified query below): The recommended indexes are an integral part of this optimization effort and should be created before testing the execution duration of the optimized query.
  3. Replace In Subquery With Correlated Exists (modified query below): In many cases, an EXISTS subquery with a correlated condition will perform better than a non correlated IN subquery.
  4. Use Numeric Column Types For Numeric Values (query line: 8): Referencing a numeric value (e.g. 05) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  5. Use Numeric Column Types For Numeric Values (query line: 10): Referencing a numeric value (e.g. 10) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  6. Use Numeric Column Types For Numeric Values (query line: 12): Referencing a numeric value (e.g. 15) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  7. Use Numeric Column Types For Numeric Values (query line: 14): Referencing a numeric value (e.g. 20) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  8. Use Numeric Column Types For Numeric Values (query line: 16): Referencing a numeric value (e.g. 25) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  9. Use Numeric Column Types For Numeric Values (query line: 18): Referencing a numeric value (e.g. 30) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  10. Use Numeric Column Types For Numeric Values (query line: 20): Referencing a numeric value (e.g. 35) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  11. Use Numeric Column Types For Numeric Values (query line: 22): Referencing a numeric value (e.g. 40) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  12. Use Numeric Column Types For Numeric Values (query line: 24): Referencing a numeric value (e.g. 45) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  13. Use Numeric Column Types For Numeric Values (query line: 26): Referencing a numeric value (e.g. 50) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
  14. Use Numeric Column Types For Numeric Values (query line: 28): Referencing a numeric value (e.g. 55) as a string in a WHERE clause might result in poor performance. Possible impacts of storing numbers as varchars: more space will be used, you won't be able to perform arithmetic operations, the data won't be self-validated, aggregation functions like SUM won't work, the output may sort incorrectly and more. If the column is numeric, remove the quotes from the constant value, to make sure a numeric comparison is done.
Optimal indexes for this query:
ALTER TABLE `TCE_RLT` ADD INDEX `tce_rlt_idx_ce_id` (`CE_DPN_ID`);
ALTER TABLE `TPPL_CNTR_TRAFFIC` ADD INDEX `tppl_traffic_idx_ppl_id_log_ts` (`PPL_CNTR_ID`,`LOG_TS`);
ALTER TABLE `V_CE_PPLCNTR` ADD INDEX `v_pplcntr_idx_ppl_id` (`PPL_CNTR_ID`);
The optimized query:
SELECT
        B.CE_ID,
        A.PPL_CNTR_ID,
        SUM(A.NBR_IN) ENTERS,
        SUM(A.NBR_OUT) EXITS,
        A.LOG_TS + DECODE(TO_CHAR(A.LOG_TS,
        'mi'),
        '05',
        55 / 1440,
        '10',
        50 / 1440,
        '15',
        45 / 1440,
        '20',
        40 / 1440,
        '25',
        35 / 1440,
        '30',
        30 / 1440,
        '35',
        25 / 1440,
        '40',
        20 / 1440,
        '45',
        15 / 1440,
        '50',
        10 / 1440,
        '55',
        5 / 1440,
        0) TS 
    FROM
        OUTPUTDB.TPPL_CNTR_TRAFFIC A,
        FLUX.V_CE_PPLCNTR B 
    WHERE
        A.LOG_TS BETWEEN '07-Sep-13' AND '08-Sep-13' 
        AND A.PPL_CNTR_ID = B.PPL_CNTR_ID 
        AND EXISTS (
            SELECT
                DISTINCT 1 
            FROM
                TCE_RLT 
            WHERE
                (
                    B.CE_ID = TCE_RLT.CE_DPN_ID
                )
        ) 
    GROUP BY
        B.CE_ID,
        A.PPL_CNTR_ID,
        A.LOG_TS + DECODE(TO_CHAR(A.LOG_TS,
        'mi'),
        '05',
        55 / 1440,
        '10',
        50 / 1440,
        '15',
        45 / 1440,
        '20',
        40 / 1440,
        '25',
        35 / 1440,
        '30',
        30 / 1440,
        '35',
        25 / 1440,
        '40',
        20 / 1440,
        '45',
        15 / 1440,
        '50',
        10 / 1440,
        '55',
        5 / 1440,
        0) 
    ORDER BY
        B.CE_ID,
        A.PPL_CNTR_ID,
        A.LOG_TS + DECODE(TO_CHAR(A.LOG_TS,
        'mi'),
        '05',
        55 / 1440,
        '10',
        50 / 1440,
        '15',
        45 / 1440,
        '20',
        40 / 1440,
        '25',
        35 / 1440,
        '30',
        30 / 1440,
        '35',
        25 / 1440,
        '40',
        20 / 1440,
        '45',
        15 / 1440,
        '50',
        10 / 1440,
        '55',
        5 / 1440,
        0)

Related Articles



* original question posted on StackOverflow here.