【问题标题】:Optimizing an index in a large MySQL table优化大型 MySQL 表中的索引
【发布时间】:2019-02-10 23:01:57
【问题描述】:

我有一个大表(大约 300 万条记录),主要包括以下字段:rowID (int)、deviceID (varchar(20))、格式如 1536169459 (int(10)) 的 UnixTimestamp、powerLevel具有介于 30 和 90 之间的整数 (smallint(6))。

我希望在特定时间范围内(使用 UnixTimestamp)提取特定设备 ID 且 powerLevel 高于特定数字的记录。拥有超过 300 万条记录,这需要一段时间。有没有办法创建一个可以为此优化的索引?

【问题讨论】:

标签: mysql database optimization indexing


【解决方案1】:

建议的 3 列索引仅部分有用。优化器将使用前两列,但忽略第三列。

更好:

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,查询也会运行得更快一些。并且节省了一大堆空间。

【讨论】:

    【解决方案2】:

    如果我理解正确,你希望加快这种查询速度。

    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 将随机访问 deviceID 条目的索引,然后进一步随机访问满足 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

    【讨论】:

      【解决方案3】:

      创建索引:

      DeviceId,
      PowerLevel,
      UnixTimestamp
      

      选择时,您将首先缩小到给定设备的记录集,然后将缩小到仅在正确 PowerLevel 范围内的记录。最后,对于每个 PowerLevel,它会缩小到 UnixTimestamp 的正确记录。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-03
        • 2016-05-18
        • 1970-01-01
        相关资源
        最近更新 更多