2011-01-14 9 views
0

次のUPDATEコマンドを書きましたが、サブ選択に冗長性があります。私はSQLの専門家ではなく、このクエリをより効率的にするための助けに感謝します。早めにありがとう。複数の同様のサブ選択を持つmysql updateコマンド

update trips 
    set origin = 
    (select stop_name 
    from stops 
    inner join stop_times 
    on stops.stop_id = stop_times.stop_id 
    where stop_times.trip_id = trips.trip_id 
    order by stop_sequence asc 
    limit 1) 
    , 
    destination = 
    (select stop_name 
    from stops 
    inner join stop_times 
    on stops.stop_id = stop_times.stop_id 
    where stop_times.trip_id = trips.trip_id 
    order by stop_sequence desc 
    limit 1) 
    , 
    starts = 
    (select arrival_time 
    from stop_times 
    where stop_times.trip_id = trips.trip_id 
    order by stop_sequence asc 
    limit 1) 
    , 
    ends = 
    (select arrival_time 
    from stop_times 
    where stop_times.trip_id = trips.trip_id 
    order by stop_sequence desc 
    limit 1) 
; 

以下は関連するテーブル定義です。約72K トリップ、8Kストップ、および200万ストップ時間があります。たぶん平均20?旅行ごとに を停止します(ちょうど推測)。

create table stop_times (
    trip_id varchar(255), 
    arrival_time time, 
    stop_id varchar(255), 
    stop_sequence int unsigned, 
) type=MyISAM; 

alter table stop_times add index stop_id (stop_id(5)); 
alter table stop_times add index trip_id (trip_id(5)); 

create table stops (
    stop_id varchar(255), 
    stop_name varchar(255), 
    stop_lat float, 
    stop_lon float, 
    primary key (stop_id) 
) type=MyISAM; 

create table trips (
    route_id varchar(255), 
    trip_id varchar(255), /* primary key is here */ 
    /* denormalized fields */ 
    origin varchar(255), 
    destination varchar(255), 
    starts time, 
    ends time, 
    primary key(trip_id) 
) type=MyISAM; 
alter table trips add index route_id (route_id(5)); 
+1

どのように非効率であると測定しましたか? –

+1

テーブルの定義だけでなく、旅行ごとに何回停止するかを記入してください。 –

+0

私はそれがより良い解決策に比べて非効率かどうか分かりません。私は大規模なデータセットでこれを実行しており、それは何分もかかります。限り、SQLが行く、それはあなたに見えるか? – dan

答えて

1

まず、この更新プログラムを実行してみてください、そして、trip_idとstop_sequence列

ALTER TABLE stop_times ADD PRIMARY KEY(trip_id, stop_sequence) 

が含まれるようにstop_timesにインデックスを追加します。

update trips t JOIN (
    SELECT trip_id, MIN(stop_sequence) minS, MAX(stop_sequence) maxS 
    FROM stop_times 
    GROUP BY trip_id 
) tg ON t.trip_id = tg.trip_id 
JOIN stop_times stFirst ON tg.trip_id = stFirst.trip_id AND stFirst.stop_sequence = tg.minS 
JOIN stop_times stLast ON tg.trip_id = stLast.trip_id AND stLast.stop_sequence = tg.maxS 
JOIN stops stFirstStop ON stFirst.stop_id = stFirstStop.stop_id 
JOIN stops stLastStop ON stLast.stop_id = stLastStop.stop_id 
SET t.origin = stFirstStop.stop_name, 
    t.destination = stLastStop.stop_name, 
    t.starts = stFirst.arrival_time, 
    t.ends = stLast.arrival_time 

注:INTになりますtrip_id変更をより良いパフォーマンスを提供

また、トリップテーブルにはorigin_idとdestin ation_id。後で名前を見つけるために名前を見つけるために、すべての行に名前を格納することができます。

+0

これは、内部結合または左外部結合のJOINですか?申し訳ありませんが、これは初心者の質問です。なぜこれがより速いのか少し説明できますか? – dan

+0

@dan inner join –

+0

idsの一部が実数の文字列である可能性があるため、trip_idをINTに変更できません。これらの結合を使用すると、追加インデックスを除いて、元の4つの副選択よりも速い理由を簡単に説明できますか?ありがとう。 – dan

関連する問題