設法減少表掃描次數(luise)

LuiseDalian發表於2014-01-17

點選(此處)摺疊或開啟

  1. --場景: SQL語句非常複雜,涉及dcc_ne_log和dcc_sys_log兩張表. 表中記錄分別為305 473, 5 037 050
  2. -- 目前的執行時間為300秒.

  3. SELECT DISTINCT ne_state.peer_id AS peer_name, to_char(ne_state.ne_state) AS peer_state,
  4.   (CASE WHEN ne_state.ne_state = 0 THEN
  5.      to_char(0)
  6.    ELSE
  7.      (to_char(NVL((SELECT COUNT(*) FROM dcc_ne_log
  8.                      WHERE dcc_ne_log.result <> 1
  9.                        AND peer_id = ne_state.peer_id
  10.                        AND log_time >= TRUNC(SYSDATE)
  11.                      GROUP BY(peer_id)), 0))) END) AS err_cnt,
  12.   (CASE WHEN ne_state.ne_state = 0 THEN
  13.      to_char(0)
  14.    ELSE
  15.      (to_char(NVL((SELECT COUNT(*) FROM dcc_ne_log in_dnl
  16.                      WHERE in_dnl.direction = \'recv\'
  17.                        AND in_dnl.peer_id = ne_state.peer_id
  18.                        AND log_time >= TRUNC(SYSDATE)), 0))) END) AS recv_cnt,
  19.                        
  20.   (CASE WHEN ne_state.ne_state = 0 THEN
  21.      to_char(0)
  22.    ELSE
  23.      (to_char(NVL((SELECT SUM(LENGTH) FROM dcc_ne_log in_dnl
  24.                      WHERE in_dnl.direction = \'recv\'
  25.                        AND in_dnl.peer_id = ne_state.peer_id
  26.                        AND log_time >= TRUNC(SYSDATE)), 0))) END) AS recv_bytes,
  27.                        
  28.   (CASE WHEN ne_state.ne_state = 0 THEN
  29.      to_char(0)
  30.    ELSE
  31.      (to_char(NVL((SELECT COUNT(*) FROM dcc_ne_log in_dnl
  32.                      WHERE in_dnl.direction = \'send\'
  33.                        AND in_dnl.peer_id = ne_state.peer_id
  34.                        AND log_time >= TRUNC(SYSDATE)), 0))) END) AS send_cnt,
  35.                        
  36.   (CASE WHEN ne_state.ne_state = 0 THEN
  37.      to_char(0)
  38.    ELSE
  39.      (to_char(NVL((SELECT SUM(LENGTH) FROM dcc_ne_log in_dnl
  40.                      WHERE in_dnl.direction = \'send\'
  41.                        AND in_dnl.peer_id = ne_state.peer_id
  42.                        AND log_time >= TRUNC(SYSDATE)), 0))) END) AS send_bytes
  43.   FROM dcc_ne_log, (SELECT DISTINCT dsl1.peer_id AS peer_id, NVL(ne_diconnect_info.ne_state, 1) AS ne_state
  44.                       FROM dcc_sys_log dsl1, (SELECT DISTINCT dnl.peer_id AS peer_id, DECODE(action,
  45.                                                                                       \'disconnect\', 0,
  46.                                                                                       \'connect\', 0,
  47.                                                                                       1) AS ne_state
  48.                                                 FROM dcc_sys_log dsl, dcc_ne_log dnl
  49.                                                 WHERE dsl.peer_id = dnl.peer_id
  50.                                                   AND ((dsl.action = \'disconnect\' AND dsl.cause = \'關閉對端\') OR
  51.                                                        (dsl.action = \'disconnect\' AND dsl.cause = \'連線主機失敗\'))
  52.                                                   AND log_type = \'對端互動\'
  53.                                                   AND dsl.log_time = (SELECT MAX(log_time) FROM dcc_sys_log
  54.                                                                         WHERE peer_id = dnl.peer_id
  55.                                                                           AND log_type = \'對端互動\')) ne_disconnect_info
  56.                       WHERE dsl1.peer_id = ne_disconnect_info.peer_id(+)) ne_state
  57.   WHERE ne_state.peer_id = dcc_ne_log.peer_id(+);

  58. --這個語句太複雜了,語句執行了多次表掃描和複雜連線.
  59. --為構造出err_cnt, recv_cnt, recv_byte, send_cnt, send_byte,而使用了5個SQL,這是簡化的突破口

  60. --5個欄位部分的程式碼可改寫為
  61. SELECT peer_id, COUNT(CASE WHEN RESULT <> 1 THEN 1 END) AS err_cnt,
  62.                 COUNT(CASE WHEN direction = \'recv\' THEN 1 END) AS recv_cnt,
  63.                 SUM(CASE WHEN direction = \'recv\' THEN LENGTH END) AS recv_byte,
  64.                 COUNT(CASE WHEN direction = \'send\' THEN 1 END) AS send_cnt,
  65.                 SUM(CASE WHEN direction = \'send\' THEN LENGTH END) AS send_byte
  66.   FROM dcc_ne_log
  67.   WHERE log_time >= TRUNC(SYSDATE)
  68.   GROUP BY peer_id;

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17013648/viewspace-1072012/,如需轉載,請註明出處,否則將追究法律責任。

相關文章