Oracle SQL查询调优

时间:2012-07-12 10:04:20

标签: sql oracle

我们可以调整下面的oracle sql查询吗?此查询需要花费大量时间从数据库中获取行。

SELECT T.ACCUMULATORS_INFO ACCU_INFO, T.SUBSCR_NO service_internal_id, 
T.SUBSCR_NO_RESETS service_internal_id_resets, T.*,T.MTR_TYPE_ID MTR_TYPE, 
T.ACCOUNT_NO account_internal_id, T.MTR_SUB_TYPE_ID MTR_SUB_TYPE, 
T.FILE_ID EXTRACT_FILE_ID, T.UNIT_TYPE_ID unit_type, RCV2.ISO_CODE PREV_SUBSCRIBER_CURRENCY, 
T.MTR_SOURCE_ID MTR_SOURCE, RCV1.ISO_CODE SUBSCRIBER_CURRENCY 
FROM  MTR T 
LEFT OUTER JOIN RATE_CURRENCY_REF RCV1 ON (T.CURRENCY_CODE = RCV1.CURRENCY_CODE) 
LEFT OUTER JOIN RATE_CURRENCY_REF RCV2 ON (T.PREV_CURRENCY_CODE = RCV2.CURRENCY_CODE) 
WHERE (T.CURRENCY_CODE IS NULL OR RCV1.service_version_id = ?) AND 
(T.PREV_CURRENCY_CODE IS NULL OR RCV2.service_version_id = ?) AND 
T.mod_date BETWEEN ? AND ? AND T.subscr_no = ? AND 
T.subscr_no_resets = ? 
ORDER BY T.mod_date DESC

此致 钱德拉

2 个答案:

答案 0 :(得分:0)

在不知道模型和数据的情况下优化查询总是很困难,但我会尝试这样做。

你至少应该有一个索引 rate_currency_ref (currency_code, service_version_id )
也许一个在上   mtr (mod_date, subscr_no, subscr_no_resets)

我还会调整查询以获得LEFT JOIN中的附加条件,以提高可读性(并且可能更好的优化)。

SELECT T.ACCUMULATORS_INFO ACCU_INFO, T.SUBSCR_NO service_internal_id, 
  T.SUBSCR_NO_RESETS service_internal_id_resets, T.*,T.MTR_TYPE_ID MTR_TYPE, 
  T.ACCOUNT_NO account_internal_id, T.MTR_SUB_TYPE_ID MTR_SUB_TYPE, 
  T.FILE_ID EXTRACT_FILE_ID, T.UNIT_TYPE_ID unit_type, RCV2.ISO_CODE PREV_SUBSCRIBER_CURRENCY, 
  T.MTR_SOURCE_ID MTR_SOURCE, RCV1.ISO_CODE SUBSCRIBER_CURRENCY 
FROM MTR T 
LEFT OUTER JOIN RATE_CURRENCY_REF RCV1
     ON (T.CURRENCY_CODE = RCV1.CURRENCY_CODE AND RCV1.service_version_id = ?)
LEFT OUTER JOIN RATE_CURRENCY_REF RCV2
     ON (T.PREV_CURRENCY_CODE = RCV2.CURRENCY_CODE AND RCV2.service_version_id = ?)
WHERE
  T.mod_date BETWEEN ? AND ? AND T.subscr_no = ? AND 
  T.subscr_no_resets = ? 
ORDER BY T.mod_date DESC

答案 1 :(得分:0)

SQl在...(CURRENCY_CODE IS NULL OR service_version_id_RCV1 = ?)

看起来很奇怪

无论如何,假设SQL在功能上是正确的并且尽管“Peter”建议的索引表现不佳,我会调整并重写SQL(使用子查询)以允许优化器选择更好的计划: -

SELECT tmp.*
FROM
  (SELECT T.ACCUMULATORS_INFO ACCU_INFO,
    T.SUBSCR_NO service_internal_id,
    T.SUBSCR_NO_RESETS service_internal_id_resets,
    T.*,
    T.MTR_TYPE_ID MTR_TYPE,
    T.ACCOUNT_NO account_internal_id,
    T.MTR_SUB_TYPE_ID MTR_SUB_TYPE,
    T.FILE_ID EXTRACT_FILE_ID,
    T.UNIT_TYPE_ID unit_type,
    RCV2.ISO_CODE PREV_SUBSCRIBER_CURRENCY,
    RCV2.service_version_id_RCV2,
    T.MTR_SOURCE_ID MTR_SOURCE,
    RCV1.ISO_CODE SUBSCRIBER_CURRENCY,
    RCV1.service_version_id_RCV1
  FROM MTR T
  LEFT OUTER JOIN RATE_CURRENCY_REF RCV1
  ON (T.CURRENCY_CODE = RCV1.CURRENCY_CODE)
  LEFT OUTER JOIN RATE_CURRENCY_REF RCV2
  ON (T.PREV_CURRENCY_CODE = RCV2.CURRENCY_CODE)
  WHERE T.mod_date BETWEEN ? AND ?
  AND T.subscr_no        = ?
  AND T.subscr_no_resets = ?
  ) tmp
WHERE (CURRENCY_CODE      IS NULL OR service_version_id_RCV1 = ?)
AND (PREV_CURRENCY_CODE   IS NULL OR service_version_id_RCV2 = ?)
ORDER BY mod_date DESC

我建议在MTR,RATE_CURRENCY_REF上保留以下索引:

  1. mtr(mod_date,subscr_no,subscr_no_resets)
  2. mtr(CURRENCY_CODE)
  3. mtr(PREV_CURRENCY_CODE)
  4. rate_currency_ref(currency_code)