数据库索引的全部意义在于以空间换时间。是的,索引占用的空间大致与表一样多是正常的,尤其是当表中的行像您的那样短时。
如果您切换到 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 索引到第一个符合条件的行,然后按顺序扫描它到最后一个符合条件的行。您可以阅读有关此多列索引的内容 here 和 here。
因此,您对主键列顺序的选择应基于这两种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 数据仅在每行有多个传感器时才有助于节省空间。