2014-11-25 65 views
0

我有两个表,第一个表中我有一个设备列表及其ID,帐号和设备更新其自身状态的最后时间戳。这张桌子很小,有大约5万行。多列IN SELECT与AND匹配功能

在第二张桌子上,我有所有设备的所有报告。这张桌子很重,在这个时刻有大约200.000.000(2亿)行。

大表有三列PK帐户ID,设备ID和时间戳

我从VB.NET应用

从最初的小桌子,我得到设备ID的列表,他们最后作出查询timestamp来进行查询,以便更快地获取大表中的某些行。

我面临的问题是我得到一些我不需要的数据。

例子:

accountID deviceID timestamp 
    1  A   23 
    1  A   24 
    1  A   25 
    1  B   23 

所以,如果我想最后的时间戳来获得行

SELECT* FROM clients.Events 
WHERE timestamp IN ('25','23') 
AND deviceID IN ('A','B') 
AND accountID IN ('1') 

我得到

accountID deviceID timestamp 
    1  A   23 
    1  A   25 
    1  B   23 

我需要得到

accountID deviceID timestamp 
    1  A   25 
    1  B   23 

那么,有什么办法可以将时间戳与deviceID相匹配?

我知道我可以使用MAX子句,但正如我之前所说的,事件库很大,我需要尽可能快的结果,MAX子句检查整个表并花费太多时间。

大事件表是InnoDB。

DDL

CREATE TABLE `Events` (
    `accountID` varchar(32) NOT NULL, 
    `deviceID` varchar(32) NOT NULL, 
    `timestamp` int(10) unsigned NOT NULL, 
    `statusCode` int(10) unsigned NOT NULL, 
    `latitude` double DEFAULT NULL, 
    `longitude` double DEFAULT NULL, 
    `gpsAge` int(10) unsigned DEFAULT NULL, 
    `speedKPH` double DEFAULT NULL, 
    `heading` double DEFAULT NULL, 
    `altitude` double DEFAULT NULL, 
    `transportID` varchar(32) DEFAULT NULL, 
    `inputMask` int(10) unsigned DEFAULT NULL, 
    `outputMask` int(10) unsigned DEFAULT NULL, 
    `address` varchar(90)CHARACTER SET utf8 DEFAULT NULL, 
    `dataSource` varchar(32) DEFAULT NULL, 
    `rawData` text, 
    `distanceKM` double DEFAULT NULL, 
    `odometerKM` double DEFAULT NULL, 
    `geozoneIndex` int(10) unsigned DEFAULT NULL, 
    `geozoneID` varchar(32) DEFAULT NULL, 
    `creationTime` int(10) unsigned DEFAULT NULL, 
    `streetAddress` varchar(90)CHARACTER SET utf8 DEFAULT NULL, 
    `city` varchar(40)CHARACTER SET utf8 DEFAULT NULL, 
    `stateProvince` varchar(40)CHARACTER SET utf8 DEFAULT NULL, 
    `postalCode` varchar(16)CHARACTER SET utf8 DEFAULT NULL, 
    `country` varchar(40)CHARACTER SET utf8 DEFAULT NULL, 
    `subdivision` varchar(32)CHARACTER SET utf8 DEFAULT NULL, 
    `speedLimitKPH` double DEFAULT NULL, 
    `isTollRoad` tinyint(4) DEFAULT NULL, 
    `gpsFixType` smallint(5) unsigned DEFAULT NULL, 
    `horzAccuracy` double DEFAULT NULL, 
    `vertAccuracy` double DEFAULT NULL, 
    `HDOP` double DEFAULT NULL, 
    `satelliteCount` smallint(5) unsigned DEFAULT NULL, 
    `batteryLevel` double DEFAULT NULL, 
    `batteryVolts` double DEFAULT NULL, 
    `signalStrength` double DEFAULT NULL, 
    PRIMARY KEY (`accountID` , `deviceID` , `timestamp` , `statusCode`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
+0

关系数据库通常在集合操作中工作得最好。所以把你的问题想象成两套不同的套件之一。首先设置您需要每个帐户和设备ID的最大时间戳。那么您需要将该集合加入到基本集合中以获得您要的内容 – xQbert 2014-11-25 14:06:34

+1

如果MAX()所用时间太长,则可能需要重新考虑您的索引定义。你能提供表格的DDL吗?请参阅:http://stackoverflow.com/a/6597966/1483788 – 2014-11-25 14:06:46

+0

带有GROUP by的MAX将有效地工作,前提是有合适的索引来处理,如果它的[Clustered Index](http:// dev.mysql.com/doc/refman/5.0/en/innodb-index-types.html) – StuartLC 2014-11-25 14:10:55

回答

0
SELECT CE.* 
FROM clients.events CE 
INNER JOIN (SELECT accountID, DeviceID, Max(timestamp) TS 
      FROM clients.events 
      GROUP YB accountID, DeviceID) CE2 
    on CE.AccountID=CE2.accountId 
and CE.DeviceID= CE2.DeviceID 
and CE.TimeStamp = CE2.TS 

上面让你的最大时间戳记录为每个设备和帐户 现在你只需要过滤...

WHERE DeviceID in ('A','B') and accountID = '1' and timestamp in ('25','23') 

与正确的索引应该工作有效率的。