1

我想看看对公共汽车的预计到达时间所做的预测是否有实际的信息。我写了这个查询,它超时了。难道我做错了什么?有什么优化在这里有帮助吗?

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
4

3 回答 3

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 索引,这应该会加快查询速度。

于 2012-07-12T14:38:18.440 回答
0

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

  • 在路由和代码的比较中去掉 trim(substr(...)) ,因为这会使 locationinfo 上的任何索引变得无用
  • 去掉 7 和 2179 周围的引号(假设路线和代码是数字字段)
于 2012-07-12T14:44:39.497 回答
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'
于 2012-07-12T14:35:14.420 回答