繁体   English   中英

优化大型MySQL表中的索引

[英]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可以节省空间,从而提供一点速度。
  • 当使用二级索引时,执行程序会花费一些时间在索引的BTree和数据BTree之间(由PK排序)。 通过具有PRIMARY KEY(Id) ,可以确保执行弹跳。 通过将PK更改为此,可以避免跳动。 可能会使查询速度加倍。
  • (我不确定二级索引是否将全部使用。)

另一个(次要)建议:标准化DeviceId ,以使其(可能)是2字节的SMALLINT UNSIGNED (范围为0..64K)而不是VARCHAR(20) 即使需要JOIN ,查询也会运行得更快。 并且节省了大量空间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM