【问题标题】:MariaDB / MySQL: index structure for table with one value columnMariaDB / MySQL:具有一个值列的表的索引结构
【发布时间】:2021-11-05 05:10:04
【问题描述】:

我有一个包含三列的 MariaDB MyISAM 表:

`time` int not null, 
`sensor` tinyint not null, 
`value` decimal (6,4) not null

我在 timesensor 列上有一个主键 (BTREE)

该表有 2.5 亿行,每 10 秒添加 20 条新记录。表上的所有 SELECTS 在 timetimesensor 上都有一个 WHERE 子句。

这在性能方面效果很好,但索引使用的磁盘空间比表本身还要多(2.2GB 用于数据,2.7GB 用于索引)。这对我来说似乎有点傻,因为索引基本上是整个表,这意味着 MariaDB 基本上将所有数据翻了一番。

这个表有更好的结构吗?

【问题讨论】:

  • 弹性搜索? :D
  • 什么索引? PK 处理两种类型的WHERE。请提供SHOW CREATE TABLE。请使用InnoDB,而不是 MyISAM。

标签: mysql mariadb query-optimization


【解决方案1】:

数据库索引的全部意义在于以空间换时间。是的,索引占用的空间大致与表一样多是正常的,尤其是当表中的行像您的那样短时。

如果您切换到 InnoDB 存储引擎,您的主键将成为所谓的 clustered index 也就是说,整个表将包含在主键的索引中。这样可以节省大量磁盘空间。

您应该切换到 InnoDB:MyISAM 是一个传统的存储引擎,并没有得到 MariaDB 开发人员的太多关注。如果由于某种原因 InnoDB 不适合您,请切换到更现代的 Aria 存储引擎。它类似于 MyISAM。与 MyISAM 一样,它不使用聚集的 PK 索引。

请注意:您的主键位于(time, sensor)。这意味着它最适合如下所示的 where 子句:

 WHERE time BETWEEN start AND finish

如果您重新制作主键,使其位于(sensor, time),它将适合

 WHERE sensor=somesensor AND time BETWEEN start AND finish

为什么? MySQL 随机访问 BTREE 索引到第一个符合条件的行,然后按顺序扫描它到最后一个符合条件的行。您可以阅读有关此多列索引的内容 herehere

因此,您对主键列顺序的选择应基于这两种WHERE 模式中的哪一种对性能更为关键:仅时间范围或传感器和时间范围。

如果这是我的表,我会这样定义:

CREATE TABLE series (
    time TIMESTAMP NOT NULL DEFAULT current_timestamp(),
    sensor SMALLINT(6) NOT NULL DEFAULT '0',
    value DECIMAL(6,4) NOT NULL DEFAULT '0.0000',
    PRIMARY KEY (sensor, time) USING BTREE,
    INDEX time_covering (time, sensor, value) USING BTREE
) COLLATE='utf8mb4_general_ci' ENGINE=InnoDB;

此表定义提供了一个clustered primary key,已针对按传感器和时间范围进行过滤进行了优化。而且我添加了一个覆盖索引(基本上是表的副本),仅针对按时间范围进行过滤进行了优化。有关覆盖索引的信息,请参阅this 的最后一部分。

它使用TIMESTAMP 数据类型。它们在表示时间方面与整数一样有效,并且您可以从时间算术中受益。这可以让您从传感器 3 获取昨天的读数。

WHERE time >= CURDATE() - INTERVAL 1 DAY
  AND time < CURDATE()
  AND sensor = 3

它使用SMALLINT 而不是TINYINT 作为传感器编号。您不太可能用完传感器编号,而TINYINT 数据仅在每行有多个传感器时才有助于节省空间。

【讨论】:

  • 99% 的选择是WHERE time BETWEEN x AND y and sensor IN (a,b,c,d)。但时间子句选择性极强(时间范围为6年左右,通常where中的时间子句为1小时)
  • 然后切换到(sensor, time) 索引顺序会得到一个小的改进,而且你可能不需要我建议的time_covering 索引。你会从 innodb 得到改进
  • @final - 啊哈! sensor=3sensor IN (...) 之间有显着优化。
猜你喜欢
  • 2021-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-23
  • 2019-09-30
  • 2018-07-28
  • 1970-01-01
  • 2018-01-19
相关资源
最近更新 更多