Oracle中的查询超时

时间:2012-07-12 14:27:16

标签: sql database oracle stored-procedures

我想看看对公交车的ETA做出的预测是否有实际消息。我写了这个查询,它超时了。难道我做错了什么?有什么优化可以帮到这里吗?

SELECT
P.ROUTE,
P.CODE,
(
    SELECT  COUNT(*)
    FROM    MESSAGE M
    WHERE   M.SENTDATE BETWEEN P.ARRIVAL-(20/60/24) AND P.ARRIVAL+(2/60/24)
    AND TRIM(SUBSTR(M.LOCATIONINFO, 3, 10))  = P.ROUTE
    AND TRIM(SUBSTR(M.LOCATIONINFO, 25, 10)) = P.CODE
)
CNT
FROM
(
    SELECT  *
    FROM    PREDICTION P
    WHERE   P.ARRIVAL BETWEEN TO_DATE('2012/07/04 04:30:00', 'YYYY/MM/DD HH24:MI:SS')   
    AND TO_DATE('2012/07/04 04:30:10', 'YYYY/MM/DD HH24:MI:SS')
    AND P.ROUTE ='7'
    AND P.CODE  ='2179'
)
P

3 个答案:

答案 0 :(得分:1)

要真正知道发生了什么,我们需要查看查询计划。在此期间,尝试重写您的查询以获得显式连接:

SELECT COUNT(*) as cnt
FROM (SELECT  *
      FROM PREDICTION P
      WHERE P.ARRIVAL BETWEEN TO_DATE('2012/07/04 04:30:00', 'YYYY/MM/DD HH24:MI:SS') AND TO_DATE('2012/07/04 04:30:10', 'YYYY/MM/DD HH24:MI:SS')AND
            P.ROUTE ='7' AND
            P.CODE  ='2179'
     ) P join
     MESSAGE M
     on M.SENTDATE BETWEEN P.ARRIVAL-(20/60/24) AND P.ARRIVAL+(2/60/24) AND
        TRIM(SUBSTR(M.LOCATIONINFO, 3, 10)) = P.ROUTE AND
        TRIM(SUBSTR(M.LOCATIONINFO, 25, 10)) = P.CODE

您正在进行相当复杂的加入。这两张桌有多大?他们有任何索引吗?

我建议尝试:

SELECT COUNT(*) as cnt
FROM (SELECT  *
      FROM PREDICTION P
      WHERE P.ARRIVAL BETWEEN TO_DATE('2012/07/04 04:30:00', 'YYYY/MM/DD HH24:MI:SS') AND TO_DATE('2012/07/04 04:30:10', 'YYYY/MM/DD HH24:MI:SS')AND
            P.ROUTE ='7' AND
            P.CODE  ='2179'
     ) P join
     MESSAGE M
     on M.SENTDATE BETWEEN P.ARRIVAL-(20/60/24) AND P.ARRIVAL+(2/60/24) AND
        TRIM(SUBSTR(M.LOCATIONINFO, 3, 10)) = '7' AND
        TRIM(SUBSTR(M.LOCATIONINFO, 25, 10)) = '2179'

这些是等效的。但是,在最初的情况下,Oracle可能会看到一个复杂的三部分连接,而不是使用正确的索引。在第二种情况下,它应该使用SENTDATE索引,这应该加速查询。

答案 1 :(得分:0)

试试这个,看看它是否解决了问题(并且结果是正确的!):

SELECT COUNT(M.*) CNT
FROM
    PREDICTION P
INNER JOIN
    MESSAGE M
ON  M.SENTDATE BETWEEN P.ARRIVAL-(20/60/24) AND P.ARRIVAL+(2/60/24)
AND TRIM(SUBSTR(M.LOCATIONINFO, 3, 10))  = P.ROUTE                         
AND TRIM(SUBSTR(M.LOCATIONINFO, 25, 10)) = P.CODE  
WHERE P.ARRIVAL BETWEEN TO_DATE('2012/07/04 04:30:00', 'YYYY/MM/DD HH24:MI:SS') AND TO_DATE('2012/07/04 04:30:10', 'YYYY/MM/DD HH24:MI:SS')                         
AND P.ROUTE ='7'                         
AND P.CODE  ='2179'

答案 2 :(得分:0)

除了将查询更改为使用连接而不是子查询(如已建议的那样)之外,您还可以尝试

  • 在路由和代码的比较中摆脱trim(substr(...)),因为这会使locationinfo上的任何索引无用
  • 摆脱7和2179左右的引号(假设路线和代码是数字字段)