2014-11-25 62 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') 

與正確的索引應該工作有效率的。