我有一个大表(大约3百万条记录),主要包括以下字段:rowID(int),deviceID(varchar(20)),格式为1536169459(int(10))的UnixTimestamp,powerLevel,的整数范围是30到90(smallint(6))。
我正在寻找在特定时间范围内(使用UnixTimestamp)获取特定deviceID且powerLevel高于特定数字的记录。拥有超过300万条记录,需要一段时间。有没有一种方法可以创建为此优化的索引?
答案 0 :(得分:0)
在以下位置创建索引:
DeviceId,
PowerLevel,
UnixTimestamp
选择时,将首先缩小给定设备的记录集,然后将其缩小到仅在PowerLevel范围内的那些记录。最后,对于每个PowerLevel,它将通过UnixTimestamp缩小到正确的记录。
答案 1 :(得分:0)
如果我对您的理解正确,则希望加快此类查询的速度。
SELECT something
FROM tbl
WHERE deviceID = constant
AND start <= UnixTimestamp
AND UnixTimestamp < end
AND Power >= constant
您有一个常量条件(deviceID)和两个范围标准(UnixTimestamp和Power)。 MySQL的索引是BTREE(按顺序排序),MySQL只能对SELECT进行一次索引范围扫描。
因此,您可能应该选择(deviceID, UnixTimestamp, Power)
上的索引。为了满足该查询,MySQL将随机访问设备ID条目的索引,然后进一步随机访问满足UnixTimestamp起始条件的第一行。
然后它将顺序扫描索引,并使用每个索引条目中的Power信息来决定是否应选择每一行。
您还可以使用(deviceID, Power, UnixTimestamp)
。但是在这种情况下,MySQL将找到匹配设备和电源标准的第一个条目,然后扫描索引以查看所有时间戳记的条目,以查看应选择的行。
您的性能目标是使MySQL扫描尽可能少的索引条目,因此,(deviceID, UnixTimestamp, Power)
选择似乎很有可能是更好的选择。 UnixTimestamp上的索引列可能比Power上的索引列更具选择性。 (这是我的猜测。)
ALTER TABLE tbl CREATE INDEX tbl_dev_ts_pwr (deviceID, UnixTimestamp, Power);
请看Bill Karwin的教程。还要看看马库斯·温南(Markus Winand)的https://use-the-index-luke.com
答案 2 :(得分:0)
建议的3列索引仅部分有用。优化程序将使用前两列,但忽略第三列。
更好:
INDEX(DeviceId, PowerLevel),
INDEX(DeviceId, UnixTimestamp)
为什么?
优化器将在这两者之间进行选择,这似乎更具选择性。如果时间范围为“ narrow”,则将使用第二个索引;如果没有许多具有所需PowerLevel的行,则将使用第一个索引。
更好...
PRIMARY KEY
...您可能以Id
作为PK?也许(DeviceId, UnixTimestamp)
是唯一的? (或者您可以在一秒钟内获得单个设备的两个读数吗??)如果该对是唯一的,则完全摆脱Id
并拥有
PRIMARY KEY(DeviceId, UnixTimestamp),
INDEX(DeviceId, PowerLevel)
注意:
Id
可以节省空间,从而提高速度。PRIMARY KEY(Id)
,可以确保您进行弹跳。通过将PK更改为此,可以避免跳动。这可能使查询速度翻倍。另一个(次要)建议:规范DeviceId
,使其(也许)是2字节的SMALLINT UNSIGNED
(范围为0..64K)而不是VARCHAR(20)
。即使需要JOIN
,查询也会运行得更快。并节省了大量空间。