3

次の表があります。

main(rowId、posDatetime、truckId、緯度、経度、住所)

rowId: PK
posDatetime: 座標と住所の
日時 trackId
lat,lon
address: 住所文字列

行は日時順にフィードされません。

FOR EACH各トラックの最新の位置を取得するには、次のクエリトラックで DB にアクセスします。

SELECT * FROM main WHERE truckId=XXXX ORDER BY posDatetime DESC LIMIT 1

それは私が望むものを手に入れますが、それは非効率的だと感じてMAX()MAX()ます。

次のような方法はありますか:

select * from main where rowId=MAX(posDatetime).rowID GROUP BY truckId

そのようなものはありますか?

4

3 に答える 3

2

トラックに最後に述べた位置を常に迅速に与えるソリューション。別の解決策は、posDateTime と mainId の 2 つの列をトラック テーブルに追加し、トリガーのロジックを変更することです。

このソリューションでは、トリガーをサポートするバージョンの mysql があることを前提としています。

-- drop table if exists last_position_for_truck ;

CREATE TABLE if not exists `last_position_for_truck` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `truckId` int(11) unsigned NOT NULL,
  `mainId` int(11) unsigned NOT NULL,
  `posDateTime` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `truckId` (`truckId`)
) ENGINE=myisam DEFAULT CHARSET=latin1;

-- make sure there is a one to one relationship with trucks and last_position_for_truck
-- can be run multiple times
-- must be run if a new truck is added if nothing else is done to maintain the one to one relationship
insert into `last_position_for_truck` ( truckId, mainId, posDateTime )
select truckId, mainId, posDateTime from (
    select truck.id truckId, 0 mainId,  DATE_SUB(NOW(), INTERVAL 1 YEAR) `posDateTime`
    , last_position_for_truck.id last_position_for_truck_id
    from truck
    left join last_position_for_truck
    on last_position_for_truck.truckId = truck.id
) last_position_for_truck
where last_position_for_truck_id is null ;

-- DROP TRIGGER if exists main_insert_trigger ;

delimiter $$
CREATE TRIGGER main_insert_trigger AFTER insert ON main
  FOR EACH ROW BEGIN
    update last_position_for_truck 
    set posDateTime = new.posDateTime 
    , mainId = new.id
    where truckId = NEW.truckId and posDateTime < NEW.posDateTime ;
  END$$
delimiter ;

-- assume there is a truck id of 1 and 2, -35.8739731, 152.22774 is somewhere in Asutralia
insert into main( truckId, posDateTime, lat, lon, address ) values ( 2, now(), -35.8739731, 152.22774, 'Somewhere in Australia' ) ;
insert into main( truckId, posDateTime, lat, lon, address ) values ( 1, now(), -35.8739731, 152.22774, 'Somewhere in Australia' ) ;

-- see the results
select last_position_for_truck.truckId 
, last_position_for_truck.mainId
, main.lat
, main.lon
, main.`posDateTime`
from last_position_for_truck 
left join main
on main.id = last_position_for_truck.mainId
where last_position_for_truck.id in (1,2) ;

-- sample results
1   14  -35.874 152.228 2013-01-15 11:00:18
2   13  -35.874 152.228 2013-01-15 10:59:33
于 2013-01-15T00:10:51.657 に答える
0

私の知る限り、元のクエリはクエリと同じくらい効率的です。ただし、posDatetime にインデックスを作成すると、クエリが大幅に高速化され、データベースがそれほど多くの作業を行う必要がなくなります。

于 2013-01-14T07:06:14.790 に答える
0

制限のためにtruckIdとposDatetimeに結合キーを追加し、並べ替えのためにposDatetimeだけにキーを追加できます。

ALTER TABLE main
    ADD KEY 'main_cIdx_truckId_posDatetime' ( truckId, posDatetime ),
    ADD KEY 'main_idx_posDatetime' ( posDatetime );

他の行でもソートしている場合 (プリンシパルと言いました)、この行にもキーを追加してみてください。

rowId が主キーであることを確認してください。データを時系列で挿入する場合は、posDatetime ではなく、rowId で並べ替えます。

注文をスピードアップするために、時間枠を事前に選択できます。たとえば、トラックが 1 か月に 1 回確実に路上を走行している場合、結果を 1 か月のウィンドウに制限できます。

WHERE 
    truckId = n 
    AND
    posDatetime > DATE_SUB ( CURENT_DATE, INTERVAL 30 DAY )
ORDER BY
    rowId DESC
LIMIT 1
于 2013-01-14T07:30:19.563 に答える