MariaDB / MySQL:table 的索引结构,只有一个值列
MariaDB / MySQL: index structure for table with one value column
我有一个包含三列的 MariaDB MyISAM table:
`time` int not null,
`sensor` tinyint not null,
`value` decimal (6,4) not null
此外,我在 time
和 sensor
列上有一个主键 (BTREE)
table 有 2.5 亿行,每 10 秒添加 20 条新记录。 table 上的所有 SELECTS 在 time
或 time
和 sensor
.
上都有一个 WHERE 子句
这在性能方面效果很好,但索引使用的磁盘 space 比 table 本身更多(2.2GB 用于数据,2.7GB 用于索引)。这对我来说似乎有点傻,因为索引基本上是整个 table,这意味着 MariaDB 基本上将所有数据翻了一番。
这个table有更好的结构吗?
数据库索引的全部意义在于用space换取时间。是的,索引占用 space 和 table 大致一样多是正常的,尤其是当 table 像您的那样有短行时。
如果您切换到 InnoDB 存储引擎,您的主键将变成所谓的 clustered index。 也就是说,整个 table 将是包含在主键的索引中。那可以节省很多磁盘space.
你应该切换到 InnoDB:MyISAM 是一个遗留的存储引擎,没有得到 MariaDB 开发人员的太多关注。如果出于某种原因 InnoDB 不适合您,请切换到更现代的 Aria 存储引擎。它类似于 MyISAM。与 MyISAM 一样,它不使用聚簇 PK 索引。
请注意:您的主键在 (time, sensor)
上。这意味着它最适合像这样的 where 子句:
WHERE time BETWEEN start AND finish
如果您重新制作主键,使其位于 (sensor, time)
上,它将是 suitable for
WHERE sensor=somesensor AND time BETWEEN start AND finish
为什么? MySQL 随机访问 BTREE 索引到第一个符合条件的行,然后按顺序扫描到最后一个符合条件的行。您可以阅读有关多列索引的内容 here and here。
因此,您对主键列顺序的选择应基于这两个 WHERE
模式中哪一个对性能更关键:仅时间范围或传感器和时间范围。
如果这是我的 table 我会这样定义它:
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;
这个 table 定义提供了一个 clustered primary key optimized for filtering by sensor then time range. And I have added a covering index (basically a copy of the table) optimized for filtering by time range only. For information about covering indexes see the last section of this.
它使用 TIMESTAMP
数据类型。它们在将时间表示为整数方面同样高效,并且您可以从时间算术中获益。这会获取昨天传感器 3 的读数。
WHERE time >= CURDATE() - INTERVAL 1 DAY
AND time < CURDATE()
AND sensor = 3
它使用 SMALLINT
而不是 TINYINT
作为传感器编号。您不太可能 运行 超出传感器数量,并且 TINYINT
数据仅在每行中有多个传感器时才有助于节省 space。
我有一个包含三列的 MariaDB MyISAM table:
`time` int not null,
`sensor` tinyint not null,
`value` decimal (6,4) not null
此外,我在 time
和 sensor
table 有 2.5 亿行,每 10 秒添加 20 条新记录。 table 上的所有 SELECTS 在 time
或 time
和 sensor
.
这在性能方面效果很好,但索引使用的磁盘 space 比 table 本身更多(2.2GB 用于数据,2.7GB 用于索引)。这对我来说似乎有点傻,因为索引基本上是整个 table,这意味着 MariaDB 基本上将所有数据翻了一番。
这个table有更好的结构吗?
数据库索引的全部意义在于用space换取时间。是的,索引占用 space 和 table 大致一样多是正常的,尤其是当 table 像您的那样有短行时。
如果您切换到 InnoDB 存储引擎,您的主键将变成所谓的 clustered index。 也就是说,整个 table 将是包含在主键的索引中。那可以节省很多磁盘space.
你应该切换到 InnoDB:MyISAM 是一个遗留的存储引擎,没有得到 MariaDB 开发人员的太多关注。如果出于某种原因 InnoDB 不适合您,请切换到更现代的 Aria 存储引擎。它类似于 MyISAM。与 MyISAM 一样,它不使用聚簇 PK 索引。
请注意:您的主键在 (time, sensor)
上。这意味着它最适合像这样的 where 子句:
WHERE time BETWEEN start AND finish
如果您重新制作主键,使其位于 (sensor, time)
上,它将是 suitable for
WHERE sensor=somesensor AND time BETWEEN start AND finish
为什么? MySQL 随机访问 BTREE 索引到第一个符合条件的行,然后按顺序扫描到最后一个符合条件的行。您可以阅读有关多列索引的内容 here and here。
因此,您对主键列顺序的选择应基于这两个 WHERE
模式中哪一个对性能更关键:仅时间范围或传感器和时间范围。
如果这是我的 table 我会这样定义它:
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;
这个 table 定义提供了一个 clustered primary key optimized for filtering by sensor then time range. And I have added a covering index (basically a copy of the table) optimized for filtering by time range only. For information about covering indexes see the last section of this.
它使用 TIMESTAMP
数据类型。它们在将时间表示为整数方面同样高效,并且您可以从时间算术中获益。这会获取昨天传感器 3 的读数。
WHERE time >= CURDATE() - INTERVAL 1 DAY
AND time < CURDATE()
AND sensor = 3
它使用 SMALLINT
而不是 TINYINT
作为传感器编号。您不太可能 运行 超出传感器数量,并且 TINYINT
数据仅在每行中有多个传感器时才有助于节省 space。