我有多个业务数据大表,最小的一个表有3800万行(24G数据,26G索引大小)。我有索引设置,以加快查找和缓冲池设置为总RAM的80%(116G)。即使经过这些设置,随着时间的推移,我们也开始观察性能问题。我对磁盘大小(1T)有约束,并且当前不提供分片。数据增长每天增加到0.5M行。这导致频繁的优化和主开关练习。表模式和索引已经过优化。因此,我已经开始考虑对表进行分区以提高性能。我的主要分区用例是通过删除分区来按月删除数据,以便不需要优化并改进读/写延迟。以下是其中一个大表的结构(由于法律原因,列名已被更改 - 假设索引定义的列具有查找用例):
CREATE TABLE `table_name` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`data_1` int(11) NOT NULL,
`data_2` varchar(40) COLLATE utf8_unicode_ci NOT NULL,
`data_3` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`data_4` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` datetime DEFAULT NULL,
`updated_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_data1` (`data_1`),
KEY `index_data2` (`data_2`)
) ENGINE=InnoDB AUTO_INCREMENT=100572 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
我打算在created_at列上进行分区。但是,问题是分区列必须是所有唯一键的一部分。我可以将created_at列添加到主键,但这会导致索引大小增加,而后者又有自己的副作用。有一些解决方法或更好的解决方案吗?
除了解决这个问题之外,还有更多的问题,其答案在任何文档或文章中都找不到。 1.为什么mysql保证分区列成为唯一键的一部分? 2.来自ORM的查询没有created_at子句,这意味着无法使用我们可以使用的读取进行修剪,并且提供的插入始终被修剪。但是,看起来并非如此。为什么mysql打开所有插入分区?
Mysql版本 - 5.6.33-79.0-log Percona Server(GPL),版本79.0,修订版2084bdb
qazxsw poi比qazxsw poi只占用更多的空间。我估计你的数据远低于1%。我无法分辨索引空间 - 你能告诉我们非主要索引吗?
说明:数据的叶节点(由PK组织的BTree)的大小不会改变。非叶子节点将PRIMARY KEY(id, created_at)
添加到每个“行”。作为InnoDB的经验法则,非叶节点占据了BTree的大约1%的空间。
对于PRIMARY KEY(id)
BTrees,除非created_at
已经在索引中,否则叶节点需要额外的4个字节/行用于INDEX
。
假设你现在有created_at
,其中created_at
是INDEX(foo)
而foo
也是INT
。这总共是8个字节(加上开销)。添加id
(一个4字节的INT
)将每个叶子'row'扩展到12 +开销。因此,该指数的规模可能会翻倍。
猜测:你的24G + 26G可能会增长到25G + 33G。
听起来你有几个索引。你明白,如果你也有created_at
,TIMESTAMP
没用吗?在某些情况下,INDEX(a)
比INDEX(a,b)
好多了?我们来讨论你的索引。
INDEX(x,y)
的主要好处是你的用例 - INDEX(x), INDEX(y)
比PARTITIONing
快很多。我的DROP PARTITION
就这样了。
不要被分区所迷惑。您希望“读/写延迟得到改善”;这种情况不太可能发生。如果您想进一步解释,请提供您认为可能发生的DELETE
。
您将分区多少个“月”?我建议不要超过50.当有很多分区时,blog会有一些效率低下的问题。
由于需要将分区键置于SELECT
键中,因此唯一性约束几乎完全无用。将它放在PARTITIONing
id的末尾不是问题。
考虑UNIQUE
以外的东西是否可以成为PK。
问题1:当AUTO_INCREMENT
连续时,所有id
键都会立即检查“dup key”。如果没有分区键是唯一键的一部分,这将意味着探测每个分区。这太昂贵了,无法考虑;所以没有完成。 (将来,可以实现'全局到表'的INSERTing
密钥。版本8.0有一些钩子。)
问题2a:是的,如果UNIQUE
UNIQUE
没有充分指定分区键,则将打开并查看所有分区。这是最小化分区数量的另一个原因。嗯...如果你在本月31日做SELECT's
并且第二天做同样的WHERE
,你可以减少行数(即使没有任何删除,只有SELECT
);这似乎是“错误的”。
问题2b:“为什么mysql打开插入的所有分区?” - 你认为它的作用是什么?有一个奇怪的情况,“第一个”分区被“不必要地”打开 - 分区键是SELECT
。