为什么索引比MySQL表中的数据占用更多的空间?

问题描述 投票:2回答:2

我有一个MySQL表,在Google Cloud SQL上托管了超过10亿行。

>> SHOW CREATE TABLE depth

CREATE TABLE `depth` (
  `date` date DEFAULT NULL,
  `receive_time` datetime(3) DEFAULT NULL,
  `instrument_token` bigint(20) unsigned DEFAULT NULL,
  `level` tinyint(3) unsigned DEFAULT NULL,
  `bid_count` smallint(5) unsigned DEFAULT NULL,
  `bid_size` bigint(20) unsigned DEFAULT NULL,
  `bid_price` float DEFAULT NULL,
  `ask_price` float DEFAULT NULL,
  `ask_size` bigint(20) unsigned DEFAULT NULL,
  `ask_count` smallint(5) unsigned DEFAULT NULL,
   KEY `date_time_sym` (`date`,`receive_time`,`instrument_token`),
   KEY `date_sym_time` (`date`,`instrument_token`,`receive_time`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8

为了获取数据和索引大小,我运行查询

SHOW TABLE STATUS from mktdata where Name = "depth";

在这里,我得到一行表输出,其中包含一些重要字段的值:

Name: depth
Engine:InnoDB
Version:10
Row_format:Dynamic
Rows: 1,72,08,21,447 
Avg_row_length: 78
Index_length: 1,83,90,03,07,456
Data_length:  1,35,24,53,32,480 

问题:为什么Index_lengthData_length大?你可以在上面看到我的索引,为什么他们需要这么多空间来存储?我不太了解如何创建和存储索引,所以请从基础知识中解释。

mysql database database-design
2个回答
0
投票

具有Index_length> Data_length是罕见的,但不是“坏”或“错误”。

你没有明确的PRIMARY KEY,所以它是一个隐藏的6字节字段,有点像auto_increment。

每个辅助密钥都包含PK的副本。

Avg_row_length: 78 - 这是从Date_length / Rows计算出来的。但是,Rows是一个估计。我已经看到它被关闭了2倍或更多。

你宣布的每一栏都是NULLable;这是故意的吗?不应该大多数是NOT NULL?以下计算没有考虑列可以是NULL

但是,如果很多值都是NULL,则78个字节/行可能有效。例如,BIGINT通常需要8个字节(加上开销),但如果是NULL,则需要0个字节(加上开销)。

一个索引大小:

  • DATE为3个字节
  • DATETIME的7个字节(3)
  • BIGINT的8个字节((20)无关紧要)
  • 6个字节用于隐藏PK

总计为24个字节。

  • 24个字节
  • 每行增加20(?)字节开销
  • 时间1.45 - BTree块分裂的开销

这相当于每行64个字节。 * 1.72M行= 110GB。

由于2个索引的双倍 - 220GB。 `SHOW TABLE STATUS表示184GB。这两个数字足够接近。 (我使用的一些数字只是近似值。)

顽皮不要有明确的PRIMARY KEY。使用AUTO_INCREMENT导致4字节INT或使用巨大的8字节BIGINT耗尽空间。如果某些列的组合是唯一的,则它们可能是PK。这样做可能会缩小数据大小(通过gettring摆脱6字节的PK)并可能缩小索引(如果3个索引列中的任何一个是PK的一部分)。

有关索引的更多信息:http://mysql.rjweb.org/doc.php/index_cookbook_mysql请注意它所说的“范围”和索引。如果你在datereceive_time上使用一个范围,你所拥有的指数将不是最佳的。


2
投票

那可能发生。

你有一个重度索引表。这可能有用也可能没用。

以下是一些常见错误:

  • “我正在索引所有列” - 通常没用。
  • “我索引了我使用的每一列” - 但未能理解“复合”指数的重要性:INDEX(最后,第一)与INDEX(最后),INDEX(第一)
  • INDEX(a),INDEX(a,b) - 没有意识到第一个是多余的。
  • PRIMARY KEY(id),INDEX(id) - 没有意识到PRIMARY KEY是一个INDEX(和UNIQUE)。

SHOW CREATE TABLE并描述主要的SELECTS。然后我们可以讨论哪些INDEX是最优的,哪些可以删除。

另请注意:INDEX包含表中每行的行,并包含索引列以及指向DATA中行的指针。如果您有多个索引,它们都包含在INDEX_LENGTH中(InnoDB的PRIMARY KEY除外)。

或者,它可能是您的最佳索引集,并且索引大小比数据大。

参考链接:https://forums.mysql.com/read.php?10,390235,390352

© www.soinside.com 2019 - 2024. All rights reserved.