将 MySQL 索引添加到大表的性能影响
Posted
技术标签:
【中文标题】将 MySQL 索引添加到大表的性能影响【英文标题】:Performance Impact to Adding MySQL Index to Large Table 【发布时间】:2017-02-21 12:11:51 【问题描述】:我们想在下面的 mysql 表的 字段 3 & 4 中添加一个普通索引,并想在这样做之前了解对服务器性能的影响。例如。索引会占用额外的 RAM 并因此减慢数据库的速度吗?
我们知道最初创建索引需要时间。我们对此并不担心。相反,我们想知道是否需要升级我们的服务器,以预测在添加索引后对数据库的加载/内存压力的潜在增加。我们的 dba 坚持我们必须将 RAM 从 16GB 增加到 48GB,因为他认为新索引将保留在 RAM 中,从而导致服务器耗尽内存以进行其他操作。很高兴确认是否有必要。
提前感谢您的专家建议。
MySQL 版本:5.5.30
操作系统:CentOS
硬件配置:8 核、32G RAM、1TB 磁盘
表大小:490GB
没有。行数:67M
CREATE TABLE `mytable` (
`field_1` text NOT NULL,
`field_2` varchar(200) NOT NULL,
`field_3` varchar(100) NOT NULL,
`field_4` text NOT NULL,
`field_5` char(8) NOT NULL,
`field_6` varchar(100) NOT NULL DEFAULT '',
`field_7` varchar(100) DEFAULT '',
`field_8` varchar(20) NOT NULL,
`field_9` char(16) NOT NULL,
`field_0` varchar(25) NOT NULL,
`field_a` varchar(50) NOT NULL DEFAULT '',
`field_b` varchar(20) DEFAULT '',
`field_c` varchar(35) DEFAULT '',
`field_d` varchar(35) DEFAULT '',
`field_e` varchar(30) NOT NULL DEFAULT '',
`field_f` varchar(30) DEFAULT '',
`field_g` varchar(3) NOT NULL DEFAULT 'xx',
`field_h` varchar(50) DEFAULT '',
`field_i` varchar(100) DEFAULT '',
`field_j` char(8) NOT NULL,
`field_k` varchar(10) NOT NULL DEFAULT '',
`field_l` datetime NOT NULL,
PRIMARY KEY (`field_9`),
KEY `field_j_idx` (`field_j`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
【问题讨论】:
请记住,给这么大的表添加索引并不容易 感谢您的提醒。我们知道最初创建索引需要时间。我们对此并不担心。相反,我们想知道是否需要升级我们的服务器,以预测在添加索引后对数据库的加载/内存压力的潜在增加。我们的 dba 坚持我们必须将 RAM 从 16GB 增加到 48GB,因为他认为新索引将保留在 RAM 中,从而导致服务器耗尽内存以进行其他操作。很高兴确认是否有必要。 我更担心您的磁盘大小而不是 RAM 大小。我似乎发现更大的表在更小的 RAM 中运行——这完全取决于查询的类型以及索引和访问的随机性。例如,如果 field_9 是某种摘要或 uuid,我希望你已经死在水里了。 【参考方案1】:首先,索引存储在磁盘上,而不是内存中。 MyISAM 和 innodb 都可以将某些索引块缓存到内存中,以便更快地访问最常用的块。对于 innodb,此缓冲区的大小由 innodb_buffer_pool_size 服务器系统变量控制。
从描述中可以看出,该变量的设置不受索引的增减影响。因此,除非您决定增加此变量的大小,否则添加新索引对 MySQL 内存使用没有直接影响。
显然,向现有的大型表添加新索引会在创建索引期间对性能产生影响。添加索引后对任何插入/更新/删除操作都会有明显的影响,因为 MySQL 也必须更新额外的索引数据。
【讨论】:
感谢您的回复。我们的 dba 坚持我们必须将 RAM 从 16GB 增加到 48GB,因为他认为新索引将保留在 RAM 中,从而导致服务器耗尽内存以进行其他操作。很高兴确认是否有必要。谢谢。 @AndersonTess - 我必须支持您的 DBA 错误的观点。 (至少根据你引用他的方式。)【参考方案2】:这取决于。你有什么版本的MySQL?对于较新的版本,ALGORITHM=INPLACE
可以相对快速且轻松地添加辅助的、非唯一的索引。
您还有一个潜在的问题迫在眉睫。如果这个表真的是磁盘大小的一半,如果你确实需要做一个ALTER
不能用INPLACE
做的事情,它可能会因为磁盘空间不足而崩溃。考虑在这种情况发生之前获得更大的磁盘,和/或考虑缩小表的方法。
CHAR(8)
-- 里面有什么样的数据?如果它始终是十六进制或纯字母,则应声明为 CHARACTER SET ascii
(或 latin1
),而不是 utf8——它占用 24 个字节。由于索引,Field_j 已经翻倍了。
如果某些列具有重复值,请考虑将它们“标准化”。然后用MEDIUMINT UNSIGNED
(3 个字节,最大 16M)或INT UNSIGNED
替换大容量字符串。
(我了解您需要混淆列名,但很难给您具体建议。)
field_4
是 TEXT
,无法编入索引。请进一步描述其中的文字类型;我们或许可以提出解决方法。
我假设你建表时innodb_file_per_table=ON
?还是ON
?否则,所有希望都将落空。
【讨论】:
我们使用的是 5.5.30 对神秘的字段名称感到抱歉。数据都是没有特殊十六进制/模式的常规文本。希望这可以帮助。我们想知道我们是否需要升级我们的服务器以预测在添加索引后对数据库的加载/内存压力的潜在增加。谢谢你的建议。CHAR(8)
总是 8 个字符吗?您所说的“常规文本”是否包括日文文本?
文本字段可以被索引,只是你必须提供一个索引前缀长度。以上是关于将 MySQL 索引添加到大表的性能影响的主要内容,如果未能解决你的问题,请参考以下文章