優化SQL中的or

LDean發表於2012-01-12
快過年了,要保證庫的穩定,以免影響假期,早上來就跑了個一週的AWR,發現TOP1的sql很詭異
/* Formatted on 2012-1-12 13:43:28 (QP5 v5.149.1003.31008) */
  SELECT *
    FROM app.map p LEFT JOIN APP.PG m ON devid = p.loggerid
   WHERE (devid = 'YQ6101250003'
          AND (curdatetime BETWEEN TO_DATE ('2011-05-01 00', 'YYYY-MM-DD HH24')
                               AND TO_DATE ('2011-05-05 00', 'YYYY-MM-DD HH24')))
         OR (devid = 'YQ6101250004'
             AND (curdatetime BETWEEN TO_DATE ('2011-05-01 00',
                                               'YYYY-MM-DD HH24')
                                  AND TO_DATE ('2011-05-05 00',
                                               'YYYY-MM-DD HH24')))
         OR (devid = 'YQ6101250005'
             AND (curdatetime BETWEEN TO_DATE ('2011-05-01 00',
                                               'YYYY-MM-DD HH24')
                                  AND TO_DATE ('2011-05-05 00',
                                               'YYYY-MM-DD HH24')))
         OR (devid = 'YQ6101250002'
             AND (curdatetime BETWEEN TO_DATE ('2011-05-01 00',
                                               'YYYY-MM-DD HH24')
                                  AND TO_DATE ('2011-05-05 00',
                                               'YYYY-MM-DD HH24')))
ORDER BY devid, curdatetime;
手工跑了一下,好傢伙18分45秒,這裡使用了大量的or,這會使查詢速度相當的慢,可以改用union all
/* Formatted on 2012-1-12 14:15:00 (QP5 v5.149.1003.31008) */
SELECT *
  FROM    app.map p
       LEFT JOIN
          app.PG m
       ON devid = p.loggerid
 WHERE devid = 'YQ6101250003'
       AND curdatetime BETWEEN TO_DATE ('2011-05-01 00', 'YYYY-MM-DD HH24')
                           AND TO_DATE ('2011-05-05 00', 'YYYY-MM-DD HH24')
UNION ALL
SELECT *
  FROM    app.map p
       LEFT JOIN
          app.PG m
       ON devid = p.loggerid
 WHERE devid = 'YQ6101250004'   AND curdatetime BETWEEN TO_DATE ('2011-05-01 00', 'YYYY-MM-DD HH24')  AND TO_DATE ('2011-05-05 00', 'YYYY-MM-DD HH24')
UNION ALL
SELECT *
  FROM    app.map p
       LEFT JOIN
          app.PG m
       ON devid = p.loggerid
 WHERE devid = 'YQ6101250005'
       AND curdatetime BETWEEN TO_DATE ('2011-05-01 00', 'YYYY-MM-DD HH24')
                           AND TO_DATE ('2011-05-05 00', 'YYYY-MM-DD HH24')
UNION ALL
SELECT *
  FROM    app.map p
       LEFT JOIN
          app.PG m
       ON devid = p.loggerid
 WHERE devid = 'YQ6101250002'
       AND curdatetime BETWEEN TO_DATE ('2011-05-01 00', 'YYYY-MM-DD HH24')
                           AND TO_DATE ('2011-05-05 00', 'YYYY-MM-DD HH24')
再次查詢,2秒,哈哈就喜歡這種優化後這種幾何級增長的。聯絡了下開發人員,原來是在程式碼中拼SQL的,or的個數未知,看來要改程式碼了,都改成union all吧
當然這個例子也可以使用in來解決
/* Formatted on 2012-1-12 13:43:28 (QP5 v5.149.1003.31008) */
  SELECT *
    FROM app.map p LEFT JOIN app.PG_HH m ON devid = p.loggerid
   WHERE devid in( 'YQ6101250003', 'YQ6101250004','YQ6101250005','YQ6101250002')
             AND curdatetime BETWEEN TO_DATE ('2011-05-01 00',
                                               'YYYY-MM-DD HH24')
                                  AND TO_DATE ('2011-05-05 00',
                                               'YYYY-MM-DD HH24')
ORDER BY devid, curdatetime

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

相關文章