OracleSQL优化案例_1

复制代码
WITH latest_capital AS (
                SELECT
                    a.SECU_ID,
                    a.TRD_DT,
                    c.LIST_NEGO_SHR_TTL as FLOAT_SHR,
                    c.TTL_SHR,
                    c.END_DT,
                    ROW_NUMBER() OVER (PARTITION BY a.SECU_ID, a.TRD_DT ORDER BY c.END_DT DESC) AS rn
                FROM STK_HK_EXCH_QUOT a
                         JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                         JOIN COO_SHR_STRU c ON b.COMPANY_ID = c.CORP_ID
                WHERE c.END_DT <= a.TRD_DT
            ),
                 annual_profit AS (
                     SELECT
                         b.COMPANY_ID,
                         a.TRD_DT,
                         d.NET_PROF,
                         d.OP_TINC,
                         d.END_DT,
                         ROW_NUMBER() OVER (PARTITION BY b.COMPANY_ID, a.TRD_DT ORDER BY d.END_DT DESC) AS rn
                     FROM STK_HK_EXCH_QUOT a
                              JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                              JOIN COO_HK_INC_STMT d ON b.COMPANY_ID = d.CORP_ID
                     WHERE d.END_DT <= a.TRD_DT
                       AND EXTRACT(MONTH FROM d.END_DT) = 12
                       AND EXTRACT(DAY FROM d.END_DT) = 31
                       AND d.DATA_FLAG_CD = 102
                       AND d.NET_PROF IS NOT NULL AND d.OP_TINC IS NOT NULL
                       AND d.END_DT <= ADD_MONTHS(TRUNC(a.TRD_DT, 'YEAR') - 1, 0)
                 ),
                 ttm_net_profit AS (
                     SELECT
                         b.COMPANY_ID,
                         a.TRD_DT,
                         SUM(d.NET_PROF) AS NET_PROFIT_TTM,
                         SUM(d.OP_TINC) AS OP_TINC_TTM,
                         COUNT(DISTINCT d.END_DT) as period_count
                     FROM STK_HK_EXCH_QUOT a
                              JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                              JOIN COO_HK_INC_STMT d ON b.COMPANY_ID = d.CORP_ID
                     WHERE d.END_DT >= ADD_MONTHS(a.TRD_DT, -12)
                       AND d.END_DT < a.TRD_DT
                       AND d.DATA_FLAG_CD = 102
                       AND d.NET_PROF IS NOT NULL AND d.OP_TINC IS NOT NULL
                     GROUP BY b.COMPANY_ID, a.TRD_DT
                     HAVING COUNT(DISTINCT d.END_DT) >= 4
                 ),
                 ttm_OP_CF_NET_AMT  (
                     SELECT
                         b.COMPANY_ID,
                         a.TRD_DT,
                         SUM(d.OP_CF_NET_AMT) AS OP_CF_NET_AMT_TTM,
                         COUNT(DISTINCT d.END_DT) as period_count
                     FROM STK_HK_EXCH_QUOT a
                              JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                              JOIN COO_HK_FIN_DATA d ON b.COMPANY_ID = d.CORP_ID
                     WHERE d.END_DT >= ADD_MONTHS(a.TRD_DT, -12)
                       AND d.END_DT < a.TRD_DT
                       AND d.DATA_FLAG_CD = 102
                       AND d.OP_CF_NET_AMT IS NOT NULL 
                     GROUP BY b.COMPANY_ID, a.TRD_DT
                     HAVING COUNT(DISTINCT d.END_DT) >= 4

                    ),
                 latest_profit AS (
                     SELECT
                         b.COMPANY_ID,
                         a.TRD_DT,
                         d.NET_PROF,
                         d.OP_TINC,
                         d.END_DT,
                         ROW_NUMBER() OVER (PARTITION BY b.COMPANY_ID, a.TRD_DT ORDER BY d.END_DT DESC) AS rn
                     FROM STK_HK_EXCH_QUOT a
                              JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                              JOIN COO_HK_INC_STMT d ON b.COMPANY_ID = d.CORP_ID
                     WHERE d.END_DT <= a.TRD_DT
                       AND d.DATA_FLAG_CD = 102
                       AND d.NET_PROF IS NOT NULL AND d.OP_TINC IS NOT NULL
                 ),
                 financial_ratios AS (
                     SELECT
                         COMPANY_ID,
                         TRD_DT,
                         LATEST_PB_END_DT,
                         PB,
                         PB_NEW,
                         LATEST_OP_CF_NET_AMT
                     FROM (
                              SELECT
                                  b.COMPANY_ID,
                                  a.TRD_DT,
                                  c.END_DT AS LATEST_PB_END_DT,
                                  CASE WHEN c.BVPS IS NULL OR c.BVPS = 0 THEN 0
                                       ELSE ROUND(a.CPRC/c.BVPS,4)
                                      END AS PB,
                                  CASE WHEN c.BVPS IS NULL OR c.BVPS = 0 THEN 0
                                       ELSE ROUND(a.CPRC/c.BVPS,4)
                                      END AS PB_NEW,
                                  d.OP_CF_NET_AMT AS LATEST_OP_CF_NET_AMT,
                                  ROW_NUMBER() OVER (PARTITION BY c.CORP_ID, a.TRD_DT ORDER BY c.END_DT DESC) AS rn
                              FROM STK_HK_EXCH_QUOT a
                                       JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                                       JOIN COO_FIN_DATA_NAS c ON c.CORP_ID = b.COMPANY_ID
                                       JOIN COO_HK_FIN_DATA d ON c.CORP_ID = d.CORP_ID AND c.END_DT = d.END_DT
                                  AND c.RPT_TYPE_CD = d.RPT_TYPE_CD AND c.DATA_FLAG_CD = d.DATA_FLAG_CD
                              WHERE c.END_DT <= a.TRD_DT
                                AND c.DATA_FLAG_CD = 102
                                AND c.RPT_TYPE_CD IN (1,6,9,12)
                                AND d.OP_CF_NET_AMT IS NOT NULL
                          )
                     WHERE rn = 1
                 ),
                 period_aggregates AS (
                     SELECT
                         a.SECU_ID,
                         b.COMPANY_ID,
                         a.TRD_DT,
                         a.TRD_STS,
                         a.CPRC,
                         a.LST_CPRC,
                         a.HPRC,
                         a.LPRC,
                         a.OPRC,
                         a.TRD_AMT,
                         a.TRD_VOL,
                         a.DAY_TUROV_RATE,
                         TRUNC(a.TRD_DT, 'IW') AS WEEK_START,
                         TRUNC(a.TRD_DT, 'MM') AS MONTH_START,
                         TRUNC(a.TRD_DT, 'Q') AS QUARTER_START,
                         TRUNC(a.TRD_DT, 'YEAR') AS YEAR_START,
                         CASE
                             WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                 THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                             ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                             END AS HALF_YEAR_START,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) / 10000 AS WEEK_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) / 10000 AS WEEK_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) AS WEEK_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) AS WEEK_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) AS WEEK_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) AS WEEK_FIRST_CLOSE,
                         LAST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')
                             ORDER BY a.TRD_DT ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS WEEK_LAST_CLOSE,
                         COUNT(DISTINCT a.TRD_DT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) AS WEEK_TRADING_DAYS,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) / 10000 AS MONTH_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) / 10000 AS MONTH_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) AS MONTH_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) AS MONTH_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) AS MONTH_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) AS MONTH_FIRST_CLOSE,
                         LAST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')
                             ORDER BY a.TRD_DT ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS MONTH_LAST_CLOSE,
                         COUNT(DISTINCT a.TRD_DT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) AS MONTH_TRADING_DAYS,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q')) / 10000 AS QUARTER_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q')) / 10000 AS QUARTER_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q')) AS QUARTER_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q')) AS QUARTER_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q') ORDER BY a.TRD_DT) AS QUARTER_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q') ORDER BY a.TRD_DT) AS QUARTER_FIRST_CLOSE,
                         LAST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q')
                             ORDER BY a.TRD_DT ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS QUARTER_LAST_CLOSE,
                         COUNT(DISTINCT a.TRD_DT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'Q')) AS QUARTER_TRADING_DAYS,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END) / 10000 AS HALF_YEAR_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END) / 10000 AS HALF_YEAR_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END) AS HALF_YEAR_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END) AS HALF_YEAR_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END ORDER BY a.TRD_DT) AS HALF_YEAR_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END ORDER BY a.TRD_DT) AS HALF_YEAR_FIRST_CLOSE,
                         LAST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END ORDER BY a.TRD_DT ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS HALF_YEAR_LAST_CLOSE,
                         COUNT(DISTINCT a.TRD_DT) OVER (PARTITION BY a.SECU_ID,
                             CASE
                                 WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                                     THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
                                 ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
                                 END) AS HALF_YEAR_TRADING_DAYS,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) / 10000 AS YEAR_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) / 10000 AS YEAR_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) AS YEAR_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) AS YEAR_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) AS YEAR_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) AS YEAR_FIRST_CLOSE,
                         LAST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')
                             ORDER BY a.TRD_DT ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS YEAR_LAST_CLOSE,
                         COUNT(DISTINCT a.TRD_DT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) AS YEAR_TRADING_DAYS
                     FROM STK_HK_EXCH_QUOT a
                              JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                     WHERE a.TRD_DT > v_min_trd_dt
                 ),
                 period_calculations AS (
                     SELECT
                         pa.*,
                         lc.TTL_SHR,
                         (pa.CPRC - pa.LST_CPRC) AS DAY_CHG,
                         CASE WHEN pa.LST_CPRC = 0 THEN 0
                              ELSE (pa.CPRC - pa.LST_CPRC) * 100.0 / pa.LST_CPRC
                             END AS DAY_CHG_RAT,
                         pa.CPRC * lc.TTL_SHR AS TMKT_VAL,
                         CASE WHEN pa.DAY_TUROV_RATE = 0 THEN 0
                              ELSE pa.CPRC * (pa.TRD_VOL * 100.0 / pa.DAY_TUROV_RATE)
                             END AS FMKT_VAL,
                         CASE WHEN pa.DAY_TUROV_RATE = 0 THEN 0
                              ELSE pa.TRD_AMT * 100.0 / (pa.CPRC * (pa.TRD_VOL * 100.0 / pa.DAY_TUROV_RATE))
                             END AS TUROV_RATE,
                         CASE WHEN pa.LST_CPRC = 0 THEN 0
                              ELSE (pa.HPRC - pa.LPRC) * 100.0 / pa.LST_CPRC
                             END AS DAY_AMP,
                         ROUND(pa.WEEK_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100, 4) AS WEEK_TURNOVER_RATE,
                         ROUND((pa.WEEK_LAST_CLOSE - LAG(pa.WEEK_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.WEEK_START)) * 100.0 /
                               NULLIF(LAG(pa.WEEK_LAST_CLOSE) OVER (
                                   PARTITION BY pa.SECU_ID ORDER BY pa.WEEK_START), 0), 4) AS WEEK_CHG_RAT,
                         CASE WHEN pa.WEEK_FIRST_OPEN IS NULL OR pa.WEEK_FIRST_OPEN = 0 THEN NULL
                              ELSE ROUND((pa.WEEK_HIGH - pa.WEEK_LOW) * 100.0 / pa.WEEK_FIRST_OPEN, 4)
                             END AS WEEK_AMPLITUDE,
                         (pa.WEEK_LAST_CLOSE - LAG(pa.WEEK_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.WEEK_START)) AS WEEK_CHG,
                         CASE WHEN pa.WEEK_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.WEEK_TRD_AMT / pa.WEEK_TRADING_DAYS, 4)
                             END AS WEEK_AVG_TRD_AMT,
                         CASE WHEN pa.WEEK_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.WEEK_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100 / pa.WEEK_TRADING_DAYS, 4)
                             END AS W_AVG_TURNOVER_RATE,
                         ROUND(pa.MONTH_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100, 4) AS MONTH_TURNOVER_RATE,
                         ROUND((pa.MONTH_LAST_CLOSE - LAG(pa.MONTH_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.MONTH_START)) * 100.0 /
                               NULLIF(LAG(pa.MONTH_LAST_CLOSE) OVER (
                                   PARTITION BY pa.SECU_ID ORDER BY pa.MONTH_START), 0), 4) AS MONTH_CHG_RAT,
                         CASE WHEN pa.MONTH_FIRST_OPEN IS NULL OR pa.MONTH_FIRST_OPEN = 0 THEN NULL
                              ELSE ROUND((pa.MONTH_HIGH - pa.MONTH_LOW) * 100.0 / pa.MONTH_FIRST_OPEN, 4)
                             END AS MONTH_AMPLITUDE,
                         (pa.MONTH_LAST_CLOSE - LAG(pa.MONTH_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.MONTH_START)) AS MONTH_CHG,
                         CASE WHEN pa.MONTH_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.MONTH_TRD_AMT / pa.MONTH_TRADING_DAYS, 4)
                             END AS MONTH_AVG_TRD_AMT,
                         CASE WHEN pa.MONTH_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.MONTH_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100 / pa.MONTH_TRADING_DAYS, 4)
                             END AS M_AVG_TURNOVER_RATE,
                         ROUND(pa.QUARTER_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100, 4) AS QUARTER_TURNOVER_RATE,
                         ROUND((pa.QUARTER_LAST_CLOSE - LAG(pa.QUARTER_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.QUARTER_START)) * 100.0 /
                               NULLIF(LAG(pa.QUARTER_LAST_CLOSE) OVER (
                                   PARTITION BY pa.SECU_ID ORDER BY pa.QUARTER_START), 0), 4) AS QUARTER_CHG_RAT,
                         CASE WHEN pa.QUARTER_FIRST_OPEN IS NULL OR pa.QUARTER_FIRST_OPEN = 0 THEN NULL
                              ELSE ROUND((pa.QUARTER_HIGH - pa.QUARTER_LOW) * 100.0 / pa.QUARTER_FIRST_OPEN, 4)
                             END AS QUARTER_AMPLITUDE,
                         (pa.QUARTER_LAST_CLOSE - LAG(pa.QUARTER_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.QUARTER_START)) AS QUARTER_CHG,
                         CASE WHEN pa.QUARTER_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.QUARTER_TRD_AMT / pa.QUARTER_TRADING_DAYS, 4)
                             END AS QUARTER_AVG_TRD_AMT,
                         CASE WHEN pa.QUARTER_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.QUARTER_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100 / pa.QUARTER_TRADING_DAYS, 4)
                             END AS Q_AVG_TURNOVER_RATE,
                         ROUND(pa.HALF_YEAR_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100, 4) AS H_Y_TURNOVER_RATE,
                         ROUND((pa.HALF_YEAR_LAST_CLOSE - LAG(pa.HALF_YEAR_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.HALF_YEAR_START)) * 100.0 /
                               NULLIF(LAG(pa.HALF_YEAR_LAST_CLOSE) OVER (
                                   PARTITION BY pa.SECU_ID ORDER BY pa.HALF_YEAR_START), 0), 4) AS HALF_YEAR_CHG_RAT,
                         CASE WHEN pa.HALF_YEAR_FIRST_OPEN IS NULL OR pa.HALF_YEAR_FIRST_OPEN = 0 THEN NULL
                              ELSE ROUND((pa.HALF_YEAR_HIGH - pa.HALF_YEAR_LOW) * 100.0 / pa.HALF_YEAR_FIRST_OPEN, 4)
                             END AS HALF_YEAR_AMPLITUDE,
                         (pa.HALF_YEAR_LAST_CLOSE - LAG(pa.HALF_YEAR_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.HALF_YEAR_START)) AS HALF_YEAR_CHG,
                         CASE WHEN pa.HALF_YEAR_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.HALF_YEAR_TRD_AMT / pa.HALF_YEAR_TRADING_DAYS, 4)
                             END AS H_Y_AVG_TRD_AMT,
                         CASE WHEN pa.HALF_YEAR_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.HALF_YEAR_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100 / pa.HALF_YEAR_TRADING_DAYS, 4)
                             END AS H_Y_AVG_TURNOVER_RATE,
                         ROUND(pa.YEAR_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100, 4) AS YEAR_TURNOVER_RATE,
                         ROUND((pa.YEAR_LAST_CLOSE - LAG(pa.YEAR_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.YEAR_START)) * 100.0 /
                               NULLIF(LAG(pa.YEAR_LAST_CLOSE) OVER (
                                   PARTITION BY pa.SECU_ID ORDER BY pa.YEAR_START), 0), 4) AS YEAR_CHG_RAT,
                         CASE WHEN pa.YEAR_FIRST_OPEN IS NULL OR pa.YEAR_FIRST_OPEN = 0 THEN NULL
                              ELSE ROUND((pa.YEAR_HIGH - pa.YEAR_LOW) * 100.0 / pa.YEAR_FIRST_OPEN, 4)
                             END AS YEAR_AMPLITUDE,
                         (pa.YEAR_LAST_CLOSE - LAG(pa.YEAR_LAST_CLOSE) OVER (
                             PARTITION BY pa.SECU_ID ORDER BY pa.YEAR_START)) AS YEAR_CHG,
                         CASE WHEN pa.YEAR_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.YEAR_TRD_AMT / pa.YEAR_TRADING_DAYS, 4)
                             END AS YEAR_AVG_TRD_AMT,
                         CASE WHEN pa.YEAR_TRADING_DAYS = 0 THEN NULL
                              ELSE ROUND(pa.YEAR_TRD_VOL * 10000 / NULLIF(lc.FLOAT_SHR, 0) * 100 / pa.YEAR_TRADING_DAYS, 4)
                             END AS Y_AVG_TURNOVER_RATE
                     FROM period_aggregates pa
                              LEFT JOIN latest_capital lc ON pa.SECU_ID = lc.SECU_ID
                         AND pa.TRD_DT = lc.TRD_DT AND lc.rn = 1
                 ),
                 cumulative_data AS (
                     SELECT
                         a.SECU_ID,
                         b.COMPANY_ID,
                         a.TRD_DT,
                         TRUNC(a.TRD_DT, 'IW') AS WEEK_START,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) / 10000 AS CUM_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) / 10000 AS CUM_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) AS CUM_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) AS CUM_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) AS WEEK_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) AS WEEK_FIRST_CLOSE,
                         a.CPRC AS CURRENT_CLOSE,
                         ROW_NUMBER() OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW') ORDER BY a.TRD_DT) AS DAYS_IN_WEEK,
                         TRUNC(a.TRD_DT, 'MM') AS MONTH_START,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) / 10000 AS CUM_MONTH_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) / 10000 AS CUM_MONTH_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) AS CUM_MONTH_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM')) AS CUM_MONTH_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) AS MONTH_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) AS MONTH_FIRST_CLOSE,
                         a.CPRC AS CURRENT_MONTH_CLOSE,
                         ROW_NUMBER() OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'MM') ORDER BY a.TRD_DT) AS DAYS_IN_MONTH,
                         TRUNC(a.TRD_DT, 'YEAR') AS YEAR_START,
                         SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) / 10000 AS CUM_YEAR_TRD_AMT,
                         SUM(a.TRD_VOL) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) / 10000 AS CUM_YEAR_TRD_VOL,
                         MAX(a.HPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) AS CUM_YEAR_HIGH,
                         MIN(a.LPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR')) AS CUM_YEAR_LOW,
                         FIRST_VALUE(a.OPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) AS YEAR_FIRST_OPEN,
                         FIRST_VALUE(a.CPRC) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) AS YEAR_FIRST_CLOSE,
                         a.CPRC AS CURRENT_YEAR_CLOSE,
                         ROW_NUMBER() OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'YEAR') ORDER BY a.TRD_DT) AS DAYS_IN_YEAR
                     FROM STK_HK_EXCH_QUOT a
                              JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
                     WHERE a.TRD_DT > v_min_trd_dt
                 ),
                 base_data AS (
                     SELECT
                         pc.SECU_ID,
                         pc.COMPANY_ID,
                         pc.TRD_DT,
                         pc.TRD_STS,
                         pc.CPRC,
                         pc.DAY_CHG,
                         pc.DAY_CHG_RAT,
                         pc.TMKT_VAL,
                         pc.FMKT_VAL,
                         pc.TUROV_RATE,
                         pc.DAY_AMP,
                         ap.NET_PROF AS LAST_ANNUAL_PROFIT,
                         ap.OP_TINC AS LAST_ANNUAL_INC,
                         ap.END_DT AS ANNUAL_PROFIT_END_DT,
                         lp.NET_PROF AS LATEST_NET_PROFIT,
                         lp.OP_TINC AS LATEST_OP_TINC,
                         lp.END_DT AS LATEST_PROFIT_END_DT,
                         tnp.NET_PROFIT_TTM,
                         tnp.OP_TINC_TTM,
                         toc.OP_CF_NET_AMT_TTM,
                         fr.PB,
                         fr.PB_NEW,
                         CASE WHEN fr.LATEST_OP_CF_NET_AMT IS NOT NULL AND fr.LATEST_OP_CF_NET_AMT > 0
                                  THEN pc.CPRC * pc.TTL_SHR / fr.LATEST_OP_CF_NET_AMT
                              ELSE NULL
                             END AS PC,
                         CASE WHEN fr.LATEST_OP_CF_NET_AMT IS NULL OR fr.LATEST_OP_CF_NET_AMT <= 0 THEN NULL
                              WHEN EXTRACT(MONTH FROM fr.LATEST_PB_END_DT) = 12
                                  AND EXTRACT(DAY FROM fr.LATEST_PB_END_DT) = 31 THEN pc.CPRC * pc.TTL_SHR / fr.LATEST_OP_CF_NET_AMT
                              WHEN EXTRACT(MONTH FROM fr.LATEST_PB_END_DT) = 9
                                  AND EXTRACT(DAY FROM fr.LATEST_PB_END_DT) = 30 THEN pc.CPRC * pc.TTL_SHR / (fr.LATEST_OP_CF_NET_AMT / 3.0 * 4.0)
                              WHEN EXTRACT(MONTH FROM fr.LATEST_PB_END_DT) = 6
                                  AND EXTRACT(DAY FROM fr.LATEST_PB_END_DT) = 30 THEN pc.CPRC * pc.TTL_SHR / (fr.LATEST_OP_CF_NET_AMT * 2.0)
                              WHEN EXTRACT(MONTH FROM fr.LATEST_PB_END_DT) = 3
                                  AND EXTRACT(DAY FROM fr.LATEST_PB_END_DT) = 31 THEN pc.CPRC * pc.TTL_SHR / (fr.LATEST_OP_CF_NET_AMT * 4.0)
                              ELSE NULL
                             END AS PC_DYM,
                         pc.MONTH_TRD_AMT,
                         pc.MONTH_TRD_VOL,
                         pc.MONTH_HIGH,
                         pc.MONTH_LOW,
                         pc.MONTH_CHG_RAT,
                         pc.MONTH_TURNOVER_RATE,
                         pc.MONTH_AMPLITUDE,
                         pc.MONTH_CHG,
                         pc.MONTH_AVG_TRD_AMT,
                         pc.M_AVG_TURNOVER_RATE,
                         pc.QUARTER_TRD_AMT,
                         pc.QUARTER_TRD_VOL,
                         pc.QUARTER_HIGH,
                         pc.QUARTER_LOW,
                         pc.QUARTER_CHG_RAT,
                         pc.QUARTER_TURNOVER_RATE,
                         pc.QUARTER_AMPLITUDE,
                         pc.QUARTER_CHG,
                         pc.QUARTER_AVG_TRD_AMT,
                         pc.Q_AVG_TURNOVER_RATE,
                         pc.HALF_YEAR_TRD_AMT,
                         pc.HALF_YEAR_TRD_VOL,
                         pc.HALF_YEAR_HIGH,
                         pc.HALF_YEAR_LOW,
                         pc.HALF_YEAR_CHG_RAT,
                         pc.H_Y_TURNOVER_RATE,
                         pc.HALF_YEAR_AMPLITUDE,
                         pc.HALF_YEAR_CHG,
                         pc.H_Y_AVG_TRD_AMT,
                         pc.H_Y_AVG_TURNOVER_RATE,
                         pc.YEAR_TRD_AMT,
                         pc.YEAR_TRD_VOL,
                         pc.YEAR_HIGH,
                         pc.YEAR_LOW,
                         pc.YEAR_CHG_RAT,
                         pc.YEAR_TURNOVER_RATE,
                         pc.YEAR_AMPLITUDE,
                         pc.YEAR_CHG,
                         pc.YEAR_AVG_TRD_AMT,
                         pc.Y_AVG_TURNOVER_RATE,
                         pc.WEEK_TRD_AMT,
                         pc.WEEK_TRD_VOL,
                         pc.WEEK_HIGH,
                         pc.WEEK_LOW,
                         pc.WEEK_CHG_RAT,
                         pc.WEEK_TURNOVER_RATE,
                         pc.WEEK_AMPLITUDE,
                         pc.WEEK_AVG_TRD_AMT,
                         pc.W_AVG_TURNOVER_RATE,
                         pc.WEEK_CHG,
                         cd.CUM_TRD_AMT AS WEEK_TO_DATE_TRD_AMT,
                         cd.CUM_TRD_VOL AS WEEK_TO_DATE_TRD_VOL,
                         cd.CUM_HIGH AS WEEK_TO_DATE_HIGH,
                         cd.CUM_LOW AS WEEK_TO_DATE_LOW,
                         cd.WEEK_FIRST_OPEN,
                         cd.WEEK_FIRST_CLOSE,
                         cd.CURRENT_CLOSE,
                         cd.DAYS_IN_WEEK,
                         cd.CUM_MONTH_TRD_AMT,
                         cd.CUM_MONTH_TRD_VOL,
                         cd.CUM_MONTH_HIGH,
                         cd.CUM_MONTH_LOW,
                         cd.MONTH_FIRST_OPEN,
                         cd.MONTH_FIRST_CLOSE,
                         cd.CURRENT_MONTH_CLOSE,
                         cd.DAYS_IN_MONTH,
                         cd.CUM_YEAR_TRD_AMT,
                         cd.CUM_YEAR_TRD_VOL,
                         cd.CUM_YEAR_HIGH,
                         cd.CUM_YEAR_LOW,
                         cd.YEAR_FIRST_OPEN,
                         cd.YEAR_FIRST_CLOSE,
                         cd.CURRENT_YEAR_CLOSE,
                         cd.DAYS_IN_YEAR
                     FROM period_calculations pc
                              LEFT JOIN annual_profit ap ON pc.COMPANY_ID = ap.COMPANY_ID AND pc.TRD_DT = ap.TRD_DT AND ap.rn = 1
                              LEFT JOIN latest_profit lp ON pc.COMPANY_ID = lp.COMPANY_ID AND pc.TRD_DT = lp.TRD_DT AND lp.rn = 1
                              LEFT JOIN ttm_net_profit tnp ON pc.COMPANY_ID = tnp.COMPANY_ID AND pc.TRD_DT = tnp.TRD_DT
                              LEFT JOIN ttm_OP_CF_NET_AMT toc on pc.COMPANY_ID = toc.COMPANY_ID AND pc.TRD_DT = toc.TRD_DT
                              LEFT JOIN financial_ratios fr ON pc.COMPANY_ID = fr.COMPANY_ID AND pc.TRD_DT = fr.TRD_DT
                              LEFT JOIN cumulative_data cd ON pc.SECU_ID = cd.SECU_ID AND pc.TRD_DT = cd.TRD_DT
                 )
            SELECT
                SECU_ID,
                COMPANY_ID,
                TRD_DT,
                TRD_STS,
                CPRC,
                DAY_CHG,
                DAY_CHG_RAT,
                TMKT_VAL,
                FMKT_VAL,
                TUROV_RATE,
                DAY_AMP,
                LAST_ANNUAL_PROFIT,
                LAST_ANNUAL_INC,
                ANNUAL_PROFIT_END_DT,
                LATEST_NET_PROFIT,
                LATEST_OP_TINC,
                LATEST_PROFIT_END_DT,
                NET_PROFIT_TTM,
                OP_TINC_TTM,
                OP_CF_NET_AMT_TTM,
                PB,
                PB_NEW,
                PC,
                PC_DYM,
                CASE WHEN LAST_ANNUAL_PROFIT > 0
                         THEN TMKT_VAL / LAST_ANNUAL_PROFIT
                     ELSE NULL
                    END AS PE,
                CASE WHEN LAST_ANNUAL_INC > 0
                         THEN TMKT_VAL / LAST_ANNUAL_INC
                     ELSE NULL
                    END AS PS,
                CASE WHEN LATEST_NET_PROFIT IS NULL OR LATEST_NET_PROFIT <= 0 THEN NULL
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 12
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / LATEST_NET_PROFIT
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 9
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_NET_PROFIT / 3.0 * 4.0)
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 6
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_NET_PROFIT * 2.0)
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 3
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / (LATEST_NET_PROFIT * 4.0)
                     ELSE NULL
                    END AS PE_DYM,
                CASE WHEN LATEST_OP_TINC IS NULL OR LATEST_OP_TINC <= 0 THEN NULL
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 12
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / LATEST_OP_TINC
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 9
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_OP_TINC / 3.0 * 4.0)
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 6
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_OP_TINC * 2.0)
                     WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 3
                         AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / (LATEST_OP_TINC * 4.0)
                     ELSE NULL
                    END AS PS_DYM,
                CASE WHEN OP_CF_NET_AMT_TTM > 0 
                         THEN TMKT_VAL / OP_CF_NET_AMT_TTM   
                     ELSE NULL 
                    END AS PCTTM,
                CASE WHEN NET_PROFIT_TTM > 0
                         THEN TMKT_VAL / NET_PROFIT_TTM
                     ELSE NULL
                    END AS PETTM,
                CASE WHEN OP_TINC_TTM > 0
                         THEN TMKT_VAL / OP_TINC_TTM
                     ELSE NULL
                    END AS PSTTM,
                MONTH_TRD_AMT AS TRD_AMT_RM,
                MONTH_TRD_VOL AS TRD_VOL_RM,
                MONTH_HIGH AS HPRC_RM,
                MONTH_LOW AS LPRC_RM,
                MONTH_CHG_RAT AS CHG_RAT_RM,
                MONTH_TURNOVER_RATE AS TUROV_RATE_RM,
                MONTH_AMPLITUDE AS AMP_RAT_RM,
                MONTH_CHG AS CHG_RM,
                MONTH_AVG_TRD_AMT AS TRD_AMT_AVG_RM,
                M_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_RM,
                QUARTER_TRD_AMT AS TRD_AMT_R3M,
                QUARTER_TRD_VOL AS TRD_VOL_R3M,
                QUARTER_HIGH AS HPRC_R3M,
                QUARTER_LOW AS LPRC_R3M,
                QUARTER_CHG_RAT AS CHG_RAT_R3M,
                QUARTER_TURNOVER_RATE AS TUROV_RATE_R3M,
                QUARTER_AMPLITUDE AS AMP_RAT_R3M,
                QUARTER_CHG AS CHG_R3M,
                QUARTER_AVG_TRD_AMT AS TRD_AMT_AVG_R3M,
                Q_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_R3M,
                HALF_YEAR_TRD_AMT AS TRD_AMT_R6M,
                HALF_YEAR_TRD_VOL AS TRD_VOL_R6M,
                HALF_YEAR_HIGH AS HPRC_R6M,
                HALF_YEAR_LOW AS LPRC_R6M,
                HALF_YEAR_CHG_RAT AS CHG_RAT_R6M,
                H_Y_TURNOVER_RATE AS TUROV_RATE_R6M,
                HALF_YEAR_AMPLITUDE AS AMP_RAT_R6M,
                HALF_YEAR_CHG AS CHG_R6M,
                H_Y_AVG_TRD_AMT AS TRD_AMT_AVG_R6M,
                H_Y_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_R6M,
                YEAR_TRD_AMT AS TRD_AMT_RY,
                YEAR_TRD_VOL AS TRD_VOL_RY,
                YEAR_HIGH AS HPRC_RY,
                YEAR_LOW AS LPRC_RY,
                YEAR_CHG_RAT AS CHG_RAT_RY,
                YEAR_TURNOVER_RATE AS TUROV_RATE_RY,
                YEAR_AMPLITUDE AS AMP_RAT_RY,
                YEAR_CHG AS CHG_RY,
                YEAR_AVG_TRD_AMT AS TRD_AMT_AVG_RY,
                Y_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_RY,
                WEEK_TRD_AMT AS TRD_AMT_RW,
                WEEK_TRD_VOL AS TRD_VOL_RW,
                WEEK_HIGH AS HPRC_RW,
                WEEK_LOW AS LPRC_RW,
                WEEK_CHG_RAT AS CHG_RAT_RW,
                WEEK_TURNOVER_RATE AS TUROV_RATE_RW,
                WEEK_AMPLITUDE AS AMP_RAT_RW,
                WEEK_AVG_TRD_AMT AS TRD_AMT_AVG_RW,
                W_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_RW,
                WEEK_CHG AS CHG_RW,
                WEEK_TO_DATE_TRD_AMT AS TRD_AMT_TW,
                WEEK_TO_DATE_TRD_VOL AS TRD_VOL_TW,
                WEEK_TO_DATE_HIGH AS HPRC_TW,
                WEEK_TO_DATE_LOW AS LPRC_TW,
                CASE WHEN WEEK_FIRST_CLOSE IS NULL OR WEEK_FIRST_CLOSE = 0 THEN NULL
                     ELSE ROUND((CURRENT_CLOSE - WEEK_FIRST_CLOSE) * 100.0 / WEEK_FIRST_CLOSE, 4)
                    END AS CHG_RAT_TW,
                ROUND(WEEK_TO_DATE_TRD_VOL * 10000 / NULLIF((SELECT lc2.FLOAT_SHR FROM latest_capital lc2
                                                             WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100, 4) AS TUROV_RATE_TW,
                CASE WHEN WEEK_FIRST_OPEN IS NULL OR WEEK_FIRST_OPEN = 0 THEN NULL
                     ELSE ROUND((WEEK_TO_DATE_HIGH - WEEK_TO_DATE_LOW) * 100.0 / WEEK_FIRST_OPEN, 4)
                    END AS AMP_RAT_TW,
                (CURRENT_CLOSE - WEEK_FIRST_CLOSE) AS CHG_TW,
                CASE WHEN DAYS_IN_WEEK = 0 THEN NULL
                     ELSE ROUND(WEEK_TO_DATE_TRD_AMT / DAYS_IN_WEEK, 4)
                    END AS TRD_AMT_AVG_TW,
                CASE WHEN DAYS_IN_WEEK = 0 THEN NULL
                     ELSE ROUND(WEEK_TO_DATE_TRD_VOL * 10000 / NULLIF((SELECT lc2.FLOAT_SHR FROM latest_capital lc2
                                                                       WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100 / DAYS_IN_WEEK, 4)
                    END AS TUROV_RATE_AVG_TW,
                CUM_MONTH_TRD_AMT AS TRD_AMT_TM,
                CUM_MONTH_TRD_VOL AS TRD_VOL_TM,
                CUM_MONTH_HIGH AS HPRC_TM,
                CUM_MONTH_LOW AS LPRC_TM,
                CASE WHEN MONTH_FIRST_CLOSE IS NULL OR MONTH_FIRST_CLOSE = 0 THEN NULL
                     ELSE ROUND((CURRENT_MONTH_CLOSE - MONTH_FIRST_CLOSE) * 100.0 / MONTH_FIRST_CLOSE, 4)
                    END AS CHG_RAT_TM,
                ROUND(CUM_MONTH_TRD_VOL * 10000 / NULLIF((SELECT lc2.FLOAT_SHR FROM latest_capital lc2
                                                          WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100, 4) AS TUROV_RATE_TM,
                CASE WHEN MONTH_FIRST_OPEN IS NULL OR MONTH_FIRST_OPEN = 0 THEN NULL
                     ELSE ROUND((CUM_MONTH_HIGH - CUM_MONTH_LOW) * 100.0 / MONTH_FIRST_OPEN, 4)
                    END AS AMP_RAT_TM,
                (CURRENT_MONTH_CLOSE - MONTH_FIRST_CLOSE) AS CHG_TM,
                CASE WHEN DAYS_IN_MONTH = 0 THEN NULL
                     ELSE ROUND(CUM_MONTH_TRD_AMT / DAYS_IN_MONTH, 4)
                    END AS TRD_AMT_AVG_TM,
                CASE WHEN DAYS_IN_MONTH = 0 THEN NULL
                     ELSE ROUND(CUM_MONTH_TRD_VOL * 10000 / NULLIF((SELECT lc2.FLOAT_SHR FROM latest_capital lc2
                                                                    WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100 / DAYS_IN_MONTH, 4)
                    END AS TUROV_RATE_AVG_TM,
                CUM_YEAR_TRD_AMT AS TRD_AMT_TY,
                CUM_YEAR_TRD_VOL AS TRD_VOL_TY,
                CUM_YEAR_HIGH AS HPRC_TY,
                CUM_YEAR_LOW AS LPRC_TY,
                CASE WHEN YEAR_FIRST_CLOSE IS NULL OR YEAR_FIRST_CLOSE = 0 THEN NULL
                     ELSE ROUND((CURRENT_YEAR_CLOSE - YEAR_FIRST_CLOSE) * 100.0 / YEAR_FIRST_CLOSE, 4)
                    END AS CHG_RAT_TY,
                ROUND(CUM_YEAR_TRD_VOL * 10000 / NULLIF((SELECT lc2.FLOAT_SHR FROM latest_capital lc2
                                                         WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100, 4) AS TUROV_RATE_TY,
                CASE WHEN YEAR_FIRST_OPEN IS NULL OR YEAR_FIRST_OPEN = 0 THEN NULL
                     ELSE ROUND((CUM_YEAR_HIGH - CUM_YEAR_LOW) * 100.0 / YEAR_FIRST_OPEN, 4)
                    END AS AMP_RAT_TY,
                (CURRENT_YEAR_CLOSE - YEAR_FIRST_CLOSE) AS CHG_TY,
                CASE WHEN DAYS_IN_YEAR = 0 THEN NULL
                     ELSE ROUND(CUM_YEAR_TRD_AMT / DAYS_IN_YEAR, 4)
                    END AS TRD_AMT_AVG_TY,
                CASE WHEN DAYS_IN_YEAR = 0 THEN NULL
                     ELSE ROUND(CUM_YEAR_TRD_VOL * 10000 / NULLIF((SELECT lc2.FLOAT_SHR FROM latest_capital lc2
                                                                   WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100 / DAYS_IN_YEAR, 4)
                    END AS TUROV_RATE_AVG_TY
            FROM base_data 这段SQL帮我加一下hint优化

根据您提供的SQL代码,这是一个包含多个CTE(Common Table Expression)的复杂查询。针对这类复杂查询的Oracle SQL性能优化,我为您添加了一些关键的HINT,以改善执行计划,减少TEMP表空间的使用。

优化后的SQL(添加HINT)

复制代码
SELECT /*+ 
    -- 主查询HINT
    MATERIALIZE 
    NO_MERGE 
    LEADING(pa) 
    USE_HASH(lc) 
    FULL(pa) 
    INDEX(lc) 
    PARALLEL(4) 
    */
    SECU_ID,
    COMPANY_ID,
    TRD_DT,
    TRD_STS,
    CPRC,
    DAY_CHG,
    DAY_CHG_RAT,
    TMKT_VAL,
    FMKT_VAL,
    TUROV_RATE,
    DAY_AMP,
    LAST_ANNUAL_PROFIT,
    LAST_ANNUAL_INC,
    ANNUAL_PROFIT_END_DT,
    LATEST_NET_PROFIT,
    LATEST_OP_TINC,
    LATEST_PROFIT_END_DT,
    NET_PROFIT_TTM,
    OP_TINC_TTM,
    OP_CF_NET_AMT_TTM,
    PB,
    PB_NEW,
    PC,
    PC_DYM,
    CASE WHEN LAST_ANNUAL_PROFIT > 0
             THEN TMKT_VAL / LAST_ANNUAL_PROFIT
         ELSE NULL
        END AS PE,
    CASE WHEN LAST_ANNUAL_INC > 0
             THEN TMKT_VAL / LAST_ANNUAL_INC
         ELSE NULL
        END AS PS,
    CASE WHEN LATEST_NET_PROFIT IS NULL OR LATEST_NET_PROFIT <= 0 THEN NULL
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 12
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / LATEST_NET_PROFIT
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 9
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_NET_PROFIT / 3.0 * 4.0)
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 6
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_NET_PROFIT * 2.0)
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 3
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / (LATEST_NET_PROFIT * 4.0)
         ELSE NULL
        END AS PE_DYM,
    CASE WHEN LATEST_OP_TINC IS NULL OR LATEST_OP_TINC <= 0 THEN NULL
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 12
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / LATEST_OP_TINC
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 9
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_OP_TINC / 3.0 * 4.0)
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 6
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 30 THEN TMKT_VAL / (LATEST_OP_TINC * 2.0)
         WHEN EXTRACT(MONTH FROM LATEST_PROFIT_END_DT) = 3
             AND EXTRACT(DAY FROM LATEST_PROFIT_END_DT) = 31 THEN TMKT_VAL / (LATEST_OP_TINC * 4.0)
         ELSE NULL
        END AS PS_DYM,
    CASE WHEN OP_CF_NET_AMT_TTM > 0 
             THEN TMKT_VAL / OP_CF_NET_AMT_TTM   
         ELSE NULL 
        END AS PCTTM,
    CASE WHEN NET_PROFIT_TTM > 0
             THEN TMKT_VAL / NET_PROFIT_TTM
         ELSE NULL
        END AS PETTM,
    CASE WHEN OP_TINC_TTM > 0
             THEN TMKT_VAL / OP_TINC_TTM
         ELSE NULL
        END AS PSTTM,
    MONTH_TRD_AMT AS TRD_AMT_RM,
    MONTH_TRD_VOL AS TRD_VOL_RM,
    MONTH_HIGH AS HPRC_RM,
    MONTH_LOW AS LPRC_RM,
    MONTH_CHG_RAT AS CHG_RAT_RM,
    MONTH_TURNOVER_RATE AS TUROV_RATE_RM,
    MONTH_AMPLITUDE AS AMP_RAT_RM,
    MONTH_CHG AS CHG_RM,
    MONTH_AVG_TRD_AMT AS TRD_AMT_AVG_RM,
    M_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_RM,
    QUARTER_TRD_AMT AS TRD_AMT_R3M,
    QUARTER_TRD_VOL AS TRD_VOL_R3M,
    QUARTER_HIGH AS HPRC_R3M,
    QUARTER_LOW AS LPRC_R3M,
    QUARTER_CHG_RAT AS CHG_RAT_R3M,
    QUARTER_TURNOVER_RATE AS TUROV_RATE_R3M,
    QUARTER_AMPLITUDE AS AMP_RAT_R3M,
    QUARTER_CHG AS CHG_R3M,
    QUARTER_AVG_TRD_AMT AS TRD_AMT_AVG_R3M,
    Q_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_R3M,
    HALF_YEAR_TRD_AMT AS TRD_AMT_R6M,
    HALF_YEAR_TRD_VOL AS TRD_VOL_R6M,
    HALF_YEAR_HIGH AS HPRC_R6M,
    HALF_YEAR_LOW AS LPRC_R6M,
    HALF_YEAR_CHG_RAT AS CHG_RAT_R6M,
    H_Y_TURNOVER_RATE AS TUROV_RATE_R6M,
    HALF_YEAR_AMPLITUDE AS AMP_RAT_R6M,
    HALF_YEAR_CHG AS CHG_R6M,
    H_Y_AVG_TRD_AMT AS TRD_AMT_AVG_R6M,
    H_Y_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_R6M,
    YEAR_TRD_AMT AS TRD_AMT_RY,
    YEAR_TRD_VOL AS TRD_VOL_RY,
    YEAR_HIGH AS HPRC_RY,
    YEAR_LOW AS LPRC_RY,
    YEAR_CHG_RAT AS CHG_RAT_RY,
    YEAR_TURNOVER_RATE AS TUROV_RATE_RY,
    YEAR_AMPLITUDE AS AMP_RAT_RY,
    YEAR_CHG AS CHG_RY,
    YEAR_AVG_TRD_AMT AS TRD_AMT_AVG_RY,
    Y_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_RY,
    WEEK_TRD_AMT AS TRD_AMT_RW,
    WEEK_TRD_VOL AS TRD_VOL_RW,
    WEEK_HIGH AS HPRC_RW,
    WEEK_LOW AS LPRC_RW,
    WEEK_CHG_RAT AS CHG_RAT_RW,
    WEEK_TURNOVER_RATE AS TUROV_RATE_RW,
    WEEK_AMPLITUDE AS AMP_RAT_RW,
    WEEK_AVG_TRD_AMT AS TRD_AMT_AVG_RW,
    W_AVG_TURNOVER_RATE AS TUROV_RATE_AVG_RW,
    WEEK_CHG AS CHG_RW,
    WEEK_TO_DATE_TRD_AMT AS TRD_AMT_TW,
    WEEK_TO_DATE_TRD_VOL AS TRD_VOL_TW,
    WEEK_TO_DATE_HIGH AS HPRC_TW,
    WEEK_TO_DATE_LOW AS LPRC_TW,
    CASE WHEN WEEK_FIRST_CLOSE IS NULL OR WEEK_FIRST_CLOSE = 0 THEN NULL
         ELSE ROUND((CURRENT_CLOSE - WEEK_FIRST_CLOSE) * 100.0 / WEEK_FIRST_CLOSE, 4)
        END AS CHG_RAT_TW,
    ROUND(WEEK_TO_DATE_TRD_VOL * 10000 / NULLIF((SELECT /*+ NO_UNNEST */ lc2.FLOAT_SHR FROM latest_capital lc2
                                                 WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100, 4) AS TUROV_RATE_TW,
    CASE WHEN WEEK_FIRST_OPEN IS NULL OR WEEK_FIRST_OPEN = 0 THEN NULL
         ELSE ROUND((WEEK_TO_DATE_HIGH - WEEK_TO_DATE_LOW) * 100.0 / WEEK_FIRST_OPEN, 4)
        END AS AMP_RAT_TW,
    (CURRENT_CLOSE - WEEK_FIRST_CLOSE) AS CHG_TW,
    CASE WHEN DAYS_IN_WEEK = 0 THEN NULL
         ELSE ROUND(WEEK_TO_DATE_TRD_AMT / DAYS_IN_WEEK, 4)
        END AS TRD_AMT_AVG_TW,
    CASE WHEN DAYS_IN_WEEK = 0 THEN NULL
         ELSE ROUND(WEEK_TO_DATE_TRD_VOL * 10000 / NULLIF((SELECT /*+ NO_UNNEST */ lc2.FLOAT_SHR FROM latest_capital lc2
                                                           WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100 / DAYS_IN_WEEK, 4)
        END AS TUROV_RATE_AVG_TW,
    CUM_MONTH_TRD_AMT AS TRD_AMT_TM,
    CUM_MONTH_TRD_VOL AS TRD_VOL_TM,
    CUM_MONTH_HIGH AS HPRC_TM,
    CUM_MONTH_LOW AS LPRC_TM,
    CASE WHEN MONTH_FIRST_CLOSE IS NULL OR MONTH_FIRST_CLOSE = 0 THEN NULL
         ELSE ROUND((CURRENT_MONTH_CLOSE - MONTH_FIRST_CLOSE) * 100.0 / MONTH_FIRST_CLOSE, 4)
        END AS CHG_RAT_TM,
    ROUND(CUM_MONTH_TRD_VOL * 10000 / NULLIF((SELECT /*+ NO_UNNEST */ lc2.FLOAT_SHR FROM latest_capital lc2
                                              WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100, 4) AS TUROV_RATE_TM,
    CASE WHEN MONTH_FIRST_OPEN IS NULL OR MONTH_FIRST_OPEN = 0 THEN NULL
         ELSE ROUND((CUM_MONTH_HIGH - CUM_MONTH_LOW) * 100.0 / MONTH_FIRST_OPEN, 4)
        END AS AMP_RAT_TM,
    (CURRENT_MONTH_CLOSE - MONTH_FIRST_CLOSE) AS CHG_TM,
    CASE WHEN DAYS_IN_MONTH = 0 THEN NULL
         ELSE ROUND(CUM_MONTH_TRD_AMT / DAYS_IN_MONTH, 4)
        END AS TRD_AMT_AVG_TM,
    CASE WHEN DAYS_IN_MONTH = 0 THEN NULL
         ELSE ROUND(CUM_MONTH_TRD_VOL * 10000 / NULLIF((SELECT /*+ NO_UNNEST */ lc2.FLOAT_SHR FROM latest_capital lc2
                                                        WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100 / DAYS_IN_MONTH, 4)
        END AS TUROV_RATE_AVG_TM,
    CUM_YEAR_TRD_AMT AS TRD_AMT_TY,
    CUM_YEAR_TRD_VOL AS TRD_VOL_TY,
    CUM_YEAR_HIGH AS HPRC_TY,
    CUM_YEAR_LOW AS LPRC_TY,
    CASE WHEN YEAR_FIRST_CLOSE IS NULL OR YEAR_FIRST_CLOSE = 0 THEN NULL
         ELSE ROUND((CURRENT_YEAR_CLOSE - YEAR_FIRST_CLOSE) * 100.0 / YEAR_FIRST_CLOSE, 4)
        END AS CHG_RAT_TY,
    ROUND(CUM_YEAR_TRD_VOL * 10000 / NULLIF((SELECT /*+ NO_UNNEST */ lc2.FLOAT_SHR FROM latest_capital lc2
                                             WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100, 4) AS TUROV_RATE_TY,
    CASE WHEN YEAR_FIRST_OPEN IS NULL OR YEAR_FIRST_OPEN = 0 THEN NULL
         ELSE ROUND((CUM_YEAR_HIGH - CUM_YEAR_LOW) * 100.0 / YEAR_FIRST_OPEN, 4)
        END AS AMP_RAT_TY,
    (CURRENT_YEAR_CLOSE - YEAR_FIRST_CLOSE) AS CHG_TY,
    CASE WHEN DAYS_IN_YEAR = 0 THEN NULL
         ELSE ROUND(CUM_YEAR_TRD_AMT / DAYS_IN_YEAR, 4)
        END AS TRD_AMT_AVG_TY,
    CASE WHEN DAYS_IN_YEAR = 0 THEN NULL
         ELSE ROUND(CUM_YEAR_TRD_VOL * 10000 / NULLIF((SELECT /*+ NO_UNNEST */ lc2.FLOAT_SHR FROM latest_capital lc2
                                                       WHERE lc2.SECU_ID = base_data.SECU_ID AND lc2.TRD_DT = base_data.TRD_DT AND lc2.rn = 1), 0) * 100 / DAYS_IN_YEAR, 4)
        END AS TUROV_RATE_AVG_TY
FROM base_data

针对各个CTE的HINT优化建议

由于您的查询包含多个CTE,我建议在关键CTE的SELECT语句前也添加HINT:

1. 优化 latest_capitalCTE

复制代码
latest_capital AS (
    SELECT /*+ MATERIALIZE INDEX(a IDX_STK_HK_EXCH_QUOT_DT) USE_HASH(a b) USE_HASH(b c) */
        a.SECU_ID,
        a.TRD_DT,
        c.LIST_NEGO_SHR_TTL as FLOAT_SHR,
        c.TTL_SHR,
        c.END_DT,
        ROW_NUMBER() OVER (PARTITION BY a.SECU_ID, a.TRD_DT ORDER BY c.END_DT DESC) AS rn
    FROM STK_HK_EXCH_QUOT a
             JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
             JOIN COO_SHR_STRU c ON b.COMPANY_ID = c.CORP_ID
    WHERE c.END_DT <= a.TRD_DT
)

2. 优化 period_aggregatesCTE

这个CTE包含了大量的窗口函数,是最消耗资源的:

复制代码
period_aggregates AS (
    SELECT /*+ 
        MATERIALIZE 
        NO_MERGE 
        PARALLEL(a 4) 
        INDEX(a IDX_STK_HK_EXCH_QUOT_DT) 
        USE_HASH(a b) 
        */
        a.SECU_ID,
        b.COMPANY_ID,
        a.TRD_DT,
        a.TRD_STS,
        a.CPRC,
        a.LST_CPRC,
        a.HPRC,
        a.LPRC,
        a.OPRC,
        a.TRD_AMT,
        a.TRD_VOL,
        a.DAY_TUROV_RATE,
        TRUNC(a.TRD_DT, 'IW') AS WEEK_START,
        TRUNC(a.TRD_DT, 'MM') AS MONTH_START,
        TRUNC(a.TRD_DT, 'Q') AS QUARTER_START,
        TRUNC(a.TRD_DT, 'YEAR') AS YEAR_START,
        CASE
            WHEN EXTRACT(MONTH FROM a.TRD_DT) BETWEEN 1 AND 6
                THEN TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-01-01', 'YYYY-MM-DD')
            ELSE TO_DATE(EXTRACT(YEAR FROM a.TRD_DT) || '-07-01', 'YYYY-MM-DD')
            END AS HALF_YEAR_START,
        -- 窗口函数部分保持不变
        SUM(a.TRD_AMT) OVER (PARTITION BY a.SECU_ID, TRUNC(a.TRD_DT, 'IW')) / 10000 AS WEEK_TRD_AMT,
        -- ... 其他窗口函数
    FROM STK_HK_EXCH_QUOT a
             JOIN BASE_SECURITY_INFO b ON a.SECU_ID = b.SECURITY_ID
    WHERE a.TRD_DT > v_min_trd_dt
)

3. 优化 period_calculationsCTE

复制代码
period_calculations AS (
    SELECT /*+ 
        NO_MERGE 
        LEADING(pa) 
        USE_HASH(pa lc) 
        SWAP_JOIN_INPUTS(lc) 
        */
        pa.*,
        lc.TTL_SHR,
        (pa.CPRC - pa.LST_CPRC) AS DAY_CHG,
        -- ... 其他计算字段
    FROM period_aggregates pa
             LEFT JOIN latest_capital lc ON pa.SECU_ID = lc.SECU_ID
         AND pa.TRD_DT = lc.TRD_DT AND lc.rn = 1
)

4. 优化 base_dataCTE

复制代码
base_data AS (
    SELECT /*+ 
        NO_MERGE 
        LEADING(pc) 
        USE_HASH(pc ap) 
        USE_HASH(pc lp) 
        USE_HASH(pc tnp) 
        USE_HASH(pc toc) 
        USE_HASH(pc fr) 
        USE_HASH(pc cd) 
        NO_EXPAND 
        */
        pc.SECU_ID,
        pc.COMPANY_ID,
        pc.TRD_DT,
        -- ... 字段列表
    FROM period_calculations pc
             LEFT JOIN annual_profit ap ON pc.COMPANY_ID = ap.COMPANY_ID AND pc.TRD_DT = ap.TRD_DT AND ap.rn = 1
             LEFT JOIN latest_profit lp ON pc.COMPANY_ID = lp.COMPANY_ID AND pc.TRD_DT = lp.TRD_DT AND lp.rn = 1
             LEFT JOIN ttm_net_profit tnp ON pc.COMPANY_ID = tnp.COMPANY_ID AND pc.TRD_DT = tnp.TRD_DT
             LEFT JOIN ttm_OP_CF_NET_AMT toc on pc.COMPANY_ID = toc.COMPANY_ID AND pc.TRD_DT = toc.TRD_DT
             LEFT JOIN financial_ratios fr ON pc.COMPANY_ID = fr.COMPANY_ID AND pc.TRD_DT = fr.TRD_DT
             LEFT JOIN cumulative_data cd ON pc.SECU_ID = cd.SECU_ID AND pc.TRD_DT = cd.TRD_DT
)

关键HINT说明

MATERIALIZE:强制Oracle物化CTE结果,避免重复计算

NO_MERGE:阻止查询转换器合并视图/子查询

LEADING(table):指定驱动表

USE_HASH(table1 table2):强制使用哈希连接

PARALLEL(n):启用并行查询(n为并行度)

NO_UNNEST:阻止子查询解嵌套

INDEX(table index_name):强制使用特定索引

FULL(table):强制全表扫描

SWAP_JOIN_INPUTS(table):交换哈希连接的输入

其他优化建议

创建必要的索引

复制代码
-- 基础索引
CREATE INDEX IDX_STK_HK_EXCH_QUOT_DT ON STK_HK_EXCH_QUOT(TRD_DT);
CREATE INDEX IDX_STK_HK_EXCH_QUOT_SEC_DT ON STK_HK_EXCH_QUOT(SECU_ID, TRD_DT);
CREATE INDEX IDX_COO_SHR_STRU_CORP_DT ON COO_SHR_STRU(CORP_ID, END_DT);
CREATE INDEX IDX_COO_HK_INC_STMT_CORP_DT ON COO_HK_INC_STMT(CORP_ID, END_DT);
CREATE INDEX IDX_BASE_SECURITY_INFO_SEC ON BASE_SECURITY_INFO(SECURITY_ID);

分批处理:将增量处理改为每次处理5-7天的数据,而不是一次性处理所有数据

调整数据库参数(需要DBA权限):

复制代码
-- 增加PGA和临时表空间
ALTER SYSTEM SET pga_aggregate_target=8G SCOPE=BOTH;
ALTER SYSTEM SET workarea_size_policy=AUTO SCOPE=BOTH;

请注意,HINT的效果取决于实际的数据分布和表结构。建议在生产环境应用前,先在测试环境中验证执行计划和性能。

相关推荐
2201_756847331 小时前
uni-app怎么接极光推送 uni-app消息推送App端接入【教程】
jvm·数据库·python
一只大袋鼠2 小时前
MySQL 入门到单表操作超全总结(数据库 + SQL + 表操作 + 数据 CRUD)
数据库·mysql
hef2882 小时前
HTML5中SVG描边虚线Stroke-dasharray的配置技巧
jvm·数据库·python
wuchen10042 小时前
SQLite的外键SQL小总结
数据库·sql·sqlite
u0107475462 小时前
SQL在分布式SQL环境下的JOIN性能优化_减少跨节点数据传输
jvm·数据库·python
鸽芷咕2 小时前
一张表的三种身份证:金仓数据库 OID vs ROWID vs 自增主键选型指南
数据库·oracle
鸽芷咕2 小时前
从边缘到云端:2026年工业物联网时序数据库选型策略
数据库·物联网·时序数据库
雨墨✘2 小时前
CSS如何实现不同屏幕下的字体缩放_利用clamp函数动态调整
jvm·数据库·python
hef2882 小时前
Go语言如何刷LeetCode_Go语言LeetCode刷题教程【速学】
jvm·数据库·python