我遇到mysql时遇到了一些麻烦。我有一个表devicelog,其中存储车辆日志包括:1。设备ID 2。日期时间3。纬度4。经度
设备每分钟都会在数据库中存储一个日志。这意味着一辆车每天有1440条记录。
假设我有5000辆车,这将总计约720万行日志数据进入表中每天。
每个月我都需要生成每辆车的设备位置报告。它与另一个表名poi(兴趣点)相关,该表名存储:1。位置名称2。纬度3。经度
的最终输出应该是:deviceid、datetimer、locationname(基于devicelog提供的纬度、经度)
对于locationname,我创建了一个函数,调用存储过程通过发送行的纬度和经度来检索它,它将从poi表返回locationname
CREATE DEFINER=`root`@`localhost` PROCEDURE `SPGetGeoName`(IN `xLat` DOUBLE, IN `xLon` DOUBLE, OUT `xLocationName` NVARCHAR(1500))
BEGIN
declare lon1 float; declare lon2 float;
declare lat1 float; declare lat2 float;
declare dist float; declare pi float;
set pi = 3.1415926;
set dist=1.9;
set lon1 = xLon-dist/abs(cos(radians(xLat))*69);
set lon2 = xLon+dist/abs(cos(radians(xLat))*69);
set lat1 = xLat-(dist/69); set lat2 = xLat+(dist/69);
SET xLocationName = (SELECT locationName FROM poiTest
WHERE longitude BETWEEN lon1 AND lon2 AND
latitude BETWEEN lat1 AND lat2 AND
3956 * 2 * ASIN(SQRT( POWER(SIN((xLat-latitude)* pi/180 / 2), 2) +COS(xLat*pi/180) * COS(latitude*pi/180) *POWER(SIN((xLon-longitude) * pi /180 / 2), 2) )) < dist
ORDER BY 3956 * 2 * ASIN(SQRT( POWER(SIN((xLat-latitude)* pi/180 / 2), 2) +COS(xLat*pi/180) * COS(latitude*pi/180) *POWER(SIN((xLon-longitude) * pi /180 / 2), 2) )) ASC limit 1);
END
结果是每辆车15秒,持续1个月,粗略计算大约需要1天才能生成整个报告。
有没有办法克服这个问题?
CREATE TABLE `deviceLog` (
`tripID` int(11) NOT NULL AUTO_INCREMENT,
`latitude` float NOT NULL,
`longitude` double NOT NULL,
`rssi` smallint(6) NOT NULL,
`speed` float NOT NULL,
`course` float NOT NULL,
`hdop` float NOT NULL,
`dateTimer` datetime NOT NULL,
`gpsStat` tinyint(4) NOT NULL,
`unitStat` varchar(12) NOT NULL,
`battVolt` varchar(6) NOT NULL,
`fuelLevel` varchar(6) NOT NULL DEFAULT '0',
`fuelData` varchar(6) NOT NULL DEFAULT '0',
`ignVolt` varchar(6) NOT NULL,
`odoMeter` decimal(10,2) NOT NULL,
`deviceID` varchar(16) NOT NULL,
`chksum` varchar(2) NOT NULL,
`resol` varchar(1024) DEFAULT NULL,
`driverID` varchar(20) DEFAULT NULL,
`geoFences` varchar(255) DEFAULT NULL,
`poiLoc` varchar(255) DEFAULT NULL,
`eventStat` varchar(2) DEFAULT NULL,
`IOStat` varchar(4) DEFAULT NULL,
`groupID` varchar(2) DEFAULT NULL,
PRIMARY KEY (`tripID`),
KEY `deviceID` (`deviceID`),
KEY `dateTimer` (`dateTimer`)
) ENGINE=MyISAM AUTO_INCREMENT=3423023 DEFAULT CHARSET=latin1
CREATE TABLE `poi` (
`poiID` int(11) NOT NULL AUTO_INCREMENT,
`type` varchar(50) NOT NULL,
`locationName` varchar(200) NOT NULL,
`state` varchar(50) NOT NULL,
`city` varchar(50) NOT NULL,
`longitude` float(10,7) DEFAULT NULL,
`latitude` float DEFAULT NULL,
PRIMARY KEY (`poiID`),
KEY `lat` (`longitude`,`latitude`)
) ENGINE=MyISAM AUTO_INCREMENT=683606 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
1条答案
按热度按时间bprjcwpo1#
“专用栈”指的是大量服务器。想想成本。
有几件事是可以做到的,而不必投入硬件。
请提供
SHOW CREATE TABLE
每张table;同时,我将假设您没有(或无用的)索引。我将检查数据类型以查看可以收缩的内容—以节省磁盘空间和一些时间。我不喜欢使用的精度范围太广--
DOUBLE
有16位有效数字;69
只有2个。考虑69.172
. 看到了吗RADIAN
替代8位pi/180的函数。dist/abs(cos(radians(xLat))*69)
可以评估一次(一个小的加速)ABS()
可能没有必要。如果没有索引,查询将扫描整个表。至少有
INDEX(latitude)
以及INDEX(longitude)
. 这将使测试工作量从550k变为2k。为了把它缩小到30个,你需要一个重要的重写,艾拉http://mysql.rjweb.org/doc.php/latlng可能有一半的时间“设备”在同一个“位置”(在这种情况下,首先要查看设备自上次定位后是否没有移动。
这就带来了另一个问题——除非某个位置发生了明显的移动,否则不要存储它。这样可以节省一半的磁盘空间。
另一个想法——改变客户的期望。不要每分钟定位一次设备,而要每10分钟定位一次。仅此一项就可以将计算时间从1天更改为2.4小时。
架构注解:
FLOAT
取4字节;它们能转换成更小的数据类型吗?lat/lng不一致。看看这个有什么选择。是什么
geoFences
以及resol
?不要将(m,n)与float一起使用(例如float(10,7))。
如果要一次获取一个设备的所有数据,请更改
到
这将更好地利用“集群”。但您也必须更改为innodb。
当设备停止时,您需要消除“重复”条目。否则,您将有磁盘空间问题(和性能问题)。
不像youtube
youtube有不同的问题;其他大人物也是如此。不用费心研究了。
我建议你的首要问题是数据量。
更少的列。
行数更少。
总结信息。
24列--其中一些在几分钟内或一整天都不会改变。所以,不要一直储存它们。
把24列分开。主要问题是什么?需要多少列来支持它?也就是说,从0列构建表;你将取得更多的进展比试图削减从24列。
每15秒一排。即使“设备”已关闭?节省了很多钱。
重新计算设备所在城市的名称?但通常和上次在同一个城市。先检查一下。这将节省大量cpu时间。
使用3字节
MEDIUMINT UNSIGNED
为了“城市”。那是什么poiID
应该是,而不是4字节INT SIGNED
. 这个JOIN
当你显示名字的时候就足够便宜了。衰老。当然客户需要昨天的细节。但上个月的数据可能是courser?而去年更不详细的——甚至可能被扔了?
如果你要扔掉“旧”数据,现在是时候
PARTITION
table。所以吹扫是“瞬时的”。等等等等。