3

我有下表:

主要(rowId,posDatetime,truckId,纬度,经度,地址)

rowId: PK
posDatetime: 日期时间坐标和地址
truckId
lat,lon
address: 地址字符串

行不按日期时间顺序提供。

为了获得每辆卡车的最新位置,我用这个查询FOR EACH卡车访问了数据库:

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 添加到卡车表并更改触发器中的逻辑。

该解决方案假设您有一个支持触发器的 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 是主键。如果要按时间顺序插入数据,请按 rowId 而不是 posDatetime 排序。

为了加快订购速度,您可以预先选择一个时间窗口。例如,如果一辆卡车确实每月上路一次,您可以将结果限制在一个月的窗口内:

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