在这种情况下我应该使用分区吗?

时间:2014-01-27 08:13:05

标签: mysql database database-design partitioning database-performance

我有下表:

    CREATE TABLE `connections` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `user_id_from` int(11) NOT NULL,
 `user_id_to` int(11) NOT NULL,
 `counter` int(11) NOT NULL,
 PRIMARY KEY (`id`),
 UNIQUE KEY `to_from` (`user_id_to`,`user_id_from`),
 KEY `user_id_from` (`user_id_from`)
) ENGINE=InnoDB AUTO_INCREMENT=1559108041 DEFAULT CHARSET=utf8

它是103GB(43GB数据和59GB索引)和大约1,143,663,061行。我假设主要的性能障碍是索引大小的结果,因此解决方案可能意味着将其减少为小索引(分区)。我正在考虑添加一个DATE字段并按MONTH进行分区。每次查询最近的X个月(X将在6左右),我都可以忍受。我看到的这将导致桌子变得比现在更大。

在我进行基准测试之前,你会推荐吗?你有其他建议吗?

更新: 我在这张桌子上使用的查询:
SELECT * FROM connections WHERE user_id_to=x LIMIT 3000
SELECT * FROM connections WHERE user_id_from=x ORDER BY counter DESC LIMIT 100
SELECT user_id_from, counter FROM connections WHERE user_id_to IN (x1, x2, ..., x1000) LIMIT 500
SELECT * FROM connections WHERE user_id_to=x AND user_id_from IN (x1, x2, ..., x1000) LIMIT 1000

我通过user_id_to作为主要条件并且还通过user_id_from作为主要条件进行查询的原因是,连接是方向性的,并且我正在寻找相互连接(来自&& from->>至)。 WHERE user_id_to的行数可能非常高,WHERE user_id_from大部分都不是那么多,这就是为什么当我ORDER BY counter我没有添加索引时。

1 个答案:

答案 0 :(得分:0)

您可以通过修改唯一键来删除一个索引user_id_from(具体取决于您的查询使用它们的方式):取代to_from,将其设为 from_to (user_id_from,user_id_to),如 start-end 。那么你就不需要user_id_from上的第二个索引,因为即使不需要第二部分(user_id_from),也会使用复合索引/键user_id_to的第一部分。 / p>

所以你只需要:

PRIMARY KEY (`id`)
UNIQUE KEY `from_to` (`user_id_from`,`user_id_to`)

这是节省索引使用空间的一个变化。 (使用表格的一小部分对其进行测试,然后查看EXPLAIN结果)。 PS:当您继续进行此更改时,请删除user_id_*索引,然后创建from_to索引,以防您的磁盘限制在30 GB以内。

特别针对您的问题......
如果不需要旧数据,则可能更有意义:

  1. 删除旧行,例如user_id_to超过1年前;或者,
  2. (使用选项1) - 创建一个类似old_users的表格,如果您需要该信息,只需添加其ID和user_id_to字段。
  3. connections这样的新表格中插入旧connections_archive行,然后从connections删除。假设您要么永远不会在应用的查询中查询_archive,要么只从管理界面(即很少)查询,在这种情况下,connectionsconnections_archive的'联合'查询会影响性能可以忍受。