我在Google Cloud SQL上托管了超过10亿行的MySQL表。
>> 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_length
大于Data_length
?你可以在上面看到我的索引,为什么他们需要这么多空间来存储?我不太了解如何创建和存储索引,所以请从基础知识中解释。
答案 0 :(得分:2)
这可能发生。
你有一个重度索引的表。这可能有用也可能没用。
以下是一些常见错误:
“我正在为所有列编制索引” - 通常没用。
“我为每个使用的列编制索引” - 但未能理解“复合”索引的重要性:INDEX(last,first)与INDEX(last),INDEX(first)
INDEX(a),INDEX(a,b) - 没有意识到第一个是多余的。
PRIMARY KEY(id),INDEX(id) - 没有意识到PRIMARY KEY是一个INDEX(和UNIQUE)。
显示创建表 并描述主要的SELECTS。然后我们可以讨论哪些INDEX是最优的,哪些可以删除。
进一步说明:INDEX包含表中每行的行,并包含索引列以及指向DATA中行的指针。如果您有多个索引,它们都包含在INDEX_LENGTH中(InnoDB的PRIMARY KEY除外)。
或者,它可能是您的最佳索引集,索引大小比数据大。
答案 1 :(得分: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个字节(加上开销)。
一个索引大小:
(20)
无关紧要)总计为24个字节。
等于每行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请注意它对“范围”和索引的说法。如果您使用date
或receive_time
上的范围,则您拥有的索引将不是最佳。