Mysql对索引的分区效果

时间:2018-02-21 07:43:55

标签: mysql database database-performance partitioning

我有多个业务数据大表,最小的一个表有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

1 个答案:

答案 0 :(得分:1)

PRIMARY KEY(id, created_at)只需要比PRIMARY KEY(id)多一点的空间。我估计你的数据远低于1%。我无法告诉索引空间 - 你能告诉我们非主要索引吗?

说明:数据的叶节点(由PK组织的BTree)的大小不会改变。非叶节点将created_at添加到每个'行。根据InnoDB中的经验法则,非叶子节点占据了BTree的大约1%的空间。

对于INDEX BTrees,叶子节点需要created_at 额外的4个字节/行,除非 created_at已经在索引中。

我们假设您目前INDEX(foo) fooINTid也为INT。这总共有8个字节(加上开销)。添加created_at(一个4字节TIMESTAMP)会扩展每个叶子行#39;到12 +开销。所以, 索引的大小可能会翻倍。

猜测:你的24G + 26G可能会增长到25G + 33G。

听起来你有几个索引。您确实了解INDEX(a)如果您还有INDEX(a,b)则无用吗?在{em>某些情况下,INDEX(x,y)INDEX(x), INDEX(y)好很多?我们来讨论你的索引。

PARTITIONing的主要好处是您的使用案例 - DROP PARTITIONDELETE快得多。我的blog就是这样。

不要被分区所迷惑。您希望"读/写延迟得到改善&#34 ;;这种情况不太可能发生。如果您想进一步说明,请提供您认为可能发生的SELECT

多少"月"你会分区吗?我建议不要超过50个。PARTITIONing在存在大量分区时效率低下。

由于需要将分区键放在UNIQUE键中,因此唯一性约束几乎完全没用。将它放在AUTO_INCREMENT id的末尾不是问题。

考虑id以外的其他内容是否可以成为PK。

问题1:当INSERTing行时,会立即检查所有UNIQUE个键" dup key"。如果没有分区键是唯一键的一部分,这将意味着探测每个分区。这太昂贵了,无法考虑;所以没有完成。 (将来,可以实施'全局到表' UNIQUE密钥。版本8.0有一些挂钩这样。)

问题2a:是的,如果SELECT's WHERE未充分指定分区键,则所有分区将被打开并查看。这是最小化分区数量的另一个原因。嗯...如果你在本月31日做了SELECT并在第二天做同样的SELECT,你可以获得更少的行(即使没有任何删除,只有DROP PARTITION );这似乎"错误"。

问题2b:"为什么mysql打开插入的所有分区?" - 你认为它的作用是什么?有一个奇怪的情况,"第一"分区是不必要的'打开 - 分区键为DATETIME