2013-06-19 32 views
1

我有我的項目中執行以下查詢:使用子查詢時,Oracle查詢運行速度非常慢。這能糾正嗎?

SELECT fcr.request_id, 
      DECODE 
       (fcpt.user_concurrent_program_name, 
       'Report Set', fcr.description, 
       'Request Set Stage', fcr.description, 
       fcpt.user_concurrent_program_name 
       ) user_concurrent_program_name, 
      fcr.description, fcr.argument_text, fcr.concurrent_program_id, 
      fcr.parent_request_id, fcr.actual_start_date, 
      fcr.actual_completion_date, 
      ROUND ( (fcr.actual_completion_date - fcr.actual_start_date) 
        * 24 
        * 60, 
        4 
        ) runtime, 
      DECODE (fcr.phase_code, 'C', 'No Schedule') program_status, 
      fu.user_name, frt.responsibility_name, fcr.logfile_name 
     FROM [email protected]_link fcr, 
      [email protected]_link fcpt, 
      [email protected]_link fu, 
      [email protected]_link frt 
     WHERE fcr.concurrent_program_id = fcpt.concurrent_program_id 
     AND fcr.requested_by = fu.user_id 
     AND fcr.responsibility_id = frt.responsibility_id 
     AND fcr.responsibility_application_id = frt.application_id 
     AND fcr.actual_completion_date >= (SELECT MAX (alert_logged_time) 
              FROM allen.main_table 
             WHERE program_status = 'No Schedule') 
     AND fcr.phase_code = 'C'; 

但上面的查詢時間過長運行。當我給相應的時間作爲輸入,而不是

SELECT MAX (alert_logged_time) 
FROM allen.main_table 
WHERE program_status = 'No Schedule' 

我甚至很快得到輸出。爲什麼?無論如何要糾正這一點?

+0

嘗試在列'(PROGRAM_STATUS,ALERT_LOGGED_TIME)'上向'ALLEN.MAIN_TABLE'添加一個索引。分享並享受。 –

回答

2

我懷疑這種差異的原因是原始慢查詢有表遠程本地,而修改的查詢只有遠程表

當Oracle查詢混合的本地和遠程表時,必須決定何處發生連接。如果加入是在本地執行的,因爲默認情況下它是首選的,所有來自遠程表的數據將通過數據庫鏈接傳輸。傳輸的數據量可能比查詢的實際結果大很多倍。

另一方面,當查詢中的所有表都是遠程的時,只有查詢的結果被傳輸,而計算髮生在遠程站點。

您可以使用/*+ DRIVING_SITE (<table_alias>)*/提示來指示Oracle在指定表的站點上執行連接,從而限制來回傳輸的數據量。

將提示/*+ DRIVING_SITE(fcr) */添加到您的查詢應該使其作爲修改後的查詢執行。

+0

+1:杜,我錯過了涉及遠程表的事實。很好的想法。儘管如此,瞭解混合遠程和本地表將如何影響標量子查詢緩存會很有意思,這在我看來應該仍然適用... –

+0

添加提示,完成了這項工作。在添加提示後幾秒鐘內完成查詢。那麼,現在,這是否意味着我本地表中的數據被傳送到遠程站點,或者只是將結果傳送到遠程站點? – zephyrus

+0

@zephyrus I *認爲*數據在被髮送之前被適當地過濾。在那種情況下,我猜測只發送一行。它應該被測試。 –

1

由於您的查詢是符合Oracle的scalar subquery caching功能,我懷疑的性能下降的原因可能是缺少指數的任何(或兩者):

  • allen.main_table.program_status
  • allen.main_table.alert_logged_time
+0

是的,表格在這兩列上都沒有索引。也可能是原因。 – zephyrus

1

您可以嘗試使用連接代替

SELECT fcr.request_id, 
      DECODE 
       (fcpt.user_concurrent_program_name, 
       'Report Set', fcr.description, 
       'Request Set Stage', fcr.description, 
       fcpt.user_concurrent_program_name 
       ) user_concurrent_program_name, 
      fcr.description, fcr.argument_text, fcr.concurrent_program_id, 
      fcr.parent_request_id, fcr.actual_start_date, 
      fcr.actual_completion_date, 
      ROUND ( (fcr.actual_completion_date - fcr.actual_start_date) 
        * 24 
        * 60, 
        4 
        ) runtime, 
      DECODE (fcr.phase_code, 'C', 'No Schedule') program_status, 
      fu.user_name, frt.responsibility_name, fcr.logfile_name 
     FROM [email protected]_to_acptr fcr, 
      [email protected]_to_acptr fcpt, 
      [email protected]_to_acptr fu, 
      [email protected]_to_acptr frt, 
      (SELECT MAX (alert_logged_time) as max_time 
       FROM allen.main_table 
       WHERE program_status = 'No Schedule') SQ 
     WHERE fcr.concurrent_program_id = fcpt.concurrent_program_id 
     AND fcr.requested_by = fu.user_id 
     AND fcr.responsibility_id = frt.responsibility_id 
     AND fcr.responsibility_application_id = frt.application_id 
     AND fcr.actual_completion_date >= SQ.max_time 
     AND fcr.phase_code = 'C'; 
+0

是什麼讓你認爲聯接的子查詢可能在Oracle中表現更好?它可能對某些數據庫(如MySQL)有影響。但是Oracle的CBO應該能夠檢測到這兩個查詢是相同的...... –

+1

實際上它效果更好。以前我的查詢運行時間超過10分鐘,現在在使用完成後不到一分鐘就完成了。 – zephyrus

+0

@zephyrus:很高興知道。看到兩個執行計劃相比,會很有趣! –