优化查询

时间:2011-11-21 07:52:17

标签: mysql database

我收到了这个查询。这需要〜 0.0854 秒。我发现它有点慢。下面看我的解释

SELECT
    stops.stop_number,
    stops.stop_name_1,
    stops.stop_name_2
FROM
    tranzit.stops_times

INNER JOIN 
    tranzit.stops
ON
    (
        stops_times.stop_id = stops.stop_id
    )

INNER JOIN 
    tranzit.trips
ON
    (
        stops_times.trip_id = trips.trip_id
    )   
WHERE
    trips.route_id = 109 AND
    trips.trip_direction = 1 AND
    trips.trip_period_start <= "2011-11-24" AND
    trips.trip_period_end >= "2011-11-24"

GROUP BY
    stops.stop_id
ORDER BY
    stops_times.time_sequence ASC
LIMIT 
    0, 200

解释

id  select_type     table           type            possible_keys                                           key                         key_len     ref                             rows    Extra
1   SIMPLE          trips           index_merge     trip_id,trip_period_start,trip_period_end,trip_dir...   route_id,trip_direction     3,1         NULL                            271     Using intersect(route_id,trip_direction); Using wh...
1   SIMPLE          stops_times     ref             stop_id,trip_id                                         trip_id                     16          tranzit.trips.trip_id           24   
1   SIMPLE          stops           ref             stop_id                                                 stop_id                     3           tranzit.stops_times.stop_id     1       Using where

我有旅行指数:

Table   Non_unique  Key_name    Seq_in_index    Column_name     Collation   Cardinality     Sub_part    Packed  Null    Index_type  Comment
trips   1   agency_id   1   agency_id   A   2   NULL    NULL        BTREE    
trips   1   trip_id     1   trip_id     A   9361    NULL    NULL        BTREE    
trips   1   trip_period_start   1   trip_period_start   A   2   NULL    NULL        BTREE    
trips   1   trip_period_end     1   trip_period_end     A   2   NULL    NULL        BTREE    
trips   1   trip_direction  1   trip_direction  A   2   NULL    NULL        BTREE    
trips   1   route_id    1   route_id    A   106     NULL    NULL        BTREE    
trips   1   shape_id    1   shape_id    A   520     NULL    NULL        BTREE    
trips   1   trip_terminus   1   trip_terminus   A   301     NULL    NULL        BTREE    

停止指数

stop_number BTREE   Non Non stop_number 4626    A       
agency_id   BTREE   Non Non agency_id   1   A       
stop_id BTREE   Non Non stop_id 4626    A       

感谢您的帮助

5 个答案:

答案 0 :(得分:1)

考虑到表中有多少行,它已经很快运行了。您可以尝试一些不同的方法,例如在条件或执行简单选择时添加更多,然后运行第二个查询以获取所需的连接字段。但这些并不是你真正需要关注的地方。

重要的问题是这个查询将如何在野外表现。如果你每秒运行100次,你需要知道它是否会降级并成为瓶颈。如果它每次都可以在0.08运行,那么它仍然允许响应非常快的应用程序。

然而,最重要的策略是,如果可能并且有效,则使用memcache或类似选项来阻止始终运行查询。

答案 1 :(得分:1)

正如人们之前写的那样:

拆分为2个查询:

  1. 通过group_concat访问信息以加快速度
  2.  SELECT group_concat(trip_id) FROM trips WHERE 
         trips.route_id = 109 AND 
         trips.trip_direction = 1 AND 
         trips.trip_period_start = "2011-11-24" 
    1. 下一条信息
    2.  SELECT 
          stops.stop_number, 
          stops.stop_name_1, 
          stops.stop_name_2 
       FROM 
          tranzit.stops_times,
          tranzit.stops 
      
       WHERE 
          stops_times.stop_id = stops.stop_id
       AND
          stops_times.trip_id in ( ...)
      
      GROUP BY, ...
      

      我认为它会更快,因为你不需要查询之外的旅行表中的其他信息。

答案 2 :(得分:0)

最棘手的部分是范围查询trip_period_start, trip_period_end
我认为你可以考虑一个复合键,如: -

alter table trips
add index testing
(
  route_id, trip_direction, trip_period_start, trip_period_end
);

取决于trip_direction的唯一值,
如果总是只有几个独特的值,

alter table trips
add index testing
(
  route_id, trip_period_start, trip_period_end, trip_direction
);

答案 3 :(得分:0)

已经不到十分之一秒,你想要更快吗?好... 我会在(route_id,trip_direction,trip_period_start)上构建一个复合索引,因为它们是查询的三个关键元素。此外,按顺序将最小粒度放在索引的前面(特定路径)。然后,在那之内,它的方向,然后,日期。接下来,由于您正在进行INNER连接,因此我会先将查询的顺序与trip表进行交换。另外,在TRIP_ID上的“stops_times”表上有一个索引。通过从第一个表及其限定符开始,然后通过关系连接到子级别的tabl,您仍然可以获得元素,但是您在出行时首先针对最小的索引集运行。

select STRAIGHT_JOIN
      stops.stop_number,
      stops.stop_name_1,
      stops.stop_name_2
   from
      tranzit.trips
         join tranzit.stops_times
            on trips.trip_id = stops_times.trip_id
            join tranzit.stops
               on stops_times.stop_id = stops.stop_id
   where 
          trips.route_id = 109 
      AND trips.trip_direction = 1 
      AND trips.trip_period_start <= "2011-11-24" 
      AND trips.trip_period_end >= "2011-11-24"
   group by
      stops.stop_id
   ORDER BY
      stops_times.time_sequence
   LIMIT 
      0, 200

答案 4 :(得分:0)

我发现了一些像魅力一样的东西。我的结果编号是:

  • 0.0011
  • 0.0008
  • 0.0017(最高)
  • 0.0006(最低)
  • 0.0013

这些结果不是来自缓存。我在ttrips.agency_idtrips.route_idtrips.trip_directiontrips.trip_period_starttrips.trip_period_end)中切换了所有 WHERE ,并且它工作得很好!我无法解释为什么,但如果有人可以,我想知道为什么。非常感谢大家!

PS:即使没有trips.agency_id,它的效果也很好。

SELECT
    stops.stop_number, 
    stops.stop_name_1, 
    stops.stop_name_2
FROM 
    tranzit.stops_times,
    tranzit.stops,
    (
        SELECT 
            trips.trip_id
        FROM
            tranzit.trips
        WHERE
            trips.agency_id = 5 AND
            trips.route_id = 109 AND
            trips.trip_direction = 0 AND
            trips.trip_period_start <= "2011-12-01" AND
            trips.trip_period_end >= "2011-12-01"
        LIMIT 1
    ) as t

WHERE 
    stops_times.stop_id = stops.stop_id AND
    stops_times.trip_id in (t.trip_id)
GROUP BY
    stops_times.stop_id
ORDER BY
    stops_times.time_sequence ASC
LIMIT 
    0, 200


id  select_type     table           type        possible_keys       key         key_len     ref                             rows    Extra
1   PRIMARY         <derived2>      system      NULL                NULL        NULL        NULL                            1       Using temporary; Using filesort
1   PRIMARY         stops_times     ref         trip_id,stop_id     trip_id     16          const                           33      Using where
1   PRIMARY         stops           ref         stop_id             stop_id     3           tranzit.stops_times.stop_id     1       Using where
2   DERIVED         trips           ref         testing             testing     4                                           275     Using where