[英]Optimizing an index in a large MySQL table
我有一个大表(大约3百万条记录),主要包括以下字段:rowID(int),deviceID(varchar(20)),格式为1536169459(int(10))的UnixTimestamp,具有整数的powerLevel范围介于30到90(smallint(6))之间。
我正在寻找在特定时间范围内(使用UnixTimestamp)针对特定deviceID以及powerLevel高于特定数字的记录。 拥有超过300万条记录,需要一段时间。 有没有一种方法可以创建为此优化的索引?
在以下位置创建索引:
DeviceId,
PowerLevel,
UnixTimestamp
选择时,您将首先缩小给定设备的记录集,然后将其缩小到仅在正确PowerLevel范围内的那些记录。 最后,对于每个PowerLevel,它将通过UnixTimestamp缩小到正确的记录。
如果我对您的理解正确,则希望加快此类查询的速度。
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
建议的三列索引仅部分有用。 优化程序将使用前两列,但忽略第三列。
更好:
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
,查询也会运行得更快。 并且节省了大量空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.