MySQL分区和唯一密钥

时间:2017-07-07 13:30:23

标签: mysql partitioning

我们有一个这样的表来保存每个用户会话的登录令牌。此表未先分区,但现在我们决定对其进行分区以提高性能,因为它包含数百万行。

CREATE TABLE `tokens` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(10) unsigned DEFAULT NULL,
  `session` int(10) unsigned DEFAULT '0',
  `token` varchar(128) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `usersession` (`uid`,`session`),
  KEY `uid` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 PARTITION BY HASH(id) PARTITIONS 101;

我们计划根据“ id ”进行分区,因为它主要用于“ 选择 ”查询和因此可以有效地进行修剪。

但问题是我们维护 (uid,session) 的唯一索引,并且分区要求参与列成为唯一索引的一部分。现在,在这种情况下, (id,uid,session) 的唯一索引没有意义(将始终是唯一的)。

无论如何都可以解决这个问题,而无需手动检查(uid,session)。

2 个答案:

答案 0 :(得分:1)

可能您的唯一uid,sessionkey索引会为您执行一些业务规则。

您是否依赖DBMS执行该规则?您是使用INSERT .... ON DUPLICATE KEY UPDATE...语句,还是使用错误处理程序或其他类似的东西来处理这种唯一性?或者只是为了好的措施?

如果您依赖该唯一索引,id上对此表进行分区将无效。 Fugeddaboudit。

如果您可以删除该索引或删除其唯一约束,则可以继续进行分区。但是分区通常不适用于具有多个唯一键的表。

40M行表通常不够大,无法成为分区的理想选择。如果您遇到性能问题,则应调查改进索引。

编辑:如果您拥有现代硬件(多TB存储,大量RAM)和精心挑选的索引,那么分区(我相信)会更加麻烦,因为它值得。对于少于10 ** 9行的表来说,这确实很麻烦。如果您的自动增量id必须BIGINT而不是INT数据类型(因为int.MaxValue不够大),那么'当分区开始值得考虑时。

当所有查询都根据分区键进行过滤时,它最有效。在没有分区键的情况下过滤其他条件的速度很慢。

专业提示:关于正则表达式的古老说法也适用于分区。如果解决分区问题,现在有两个问题。

答案 1 :(得分:0)

  • 不要使用分区。它不会加速这种表格。
  • 我还没有看到BY HASH加速系统的案例。
  • PRIMARY KEY上进行分区几乎没用。
  • 一般来说,当你拥有一个非常好的自然"时,不要有AUTO_INCREMENT id。 PK - (uid, session)。或者它应该是(toke n)
  • 不要让一个索引成为另一个索引的第一部分:(uid)是多余的,给定(uid, session)
  • 如果您希望使用表情符号或中文,请考虑使用utf8mb4。另一方面,如果token是base64,那么请将其设为ascii或其他内容。

所以,我认为这会更好地工作(更小,更快等):

CREATE TABLE `tokens` (
  `uid` int(10) unsigned DEFAULT NULL,
  `session` int(10) unsigned DEFAULT '0',
  `token` VARBINARY(128) NOT NULL DEFAULT '',
  PRIMARY KEY (token),
) ENGINE=InnoDB

您搜索了以下哪些内容?

WHERE token = ...
WHERE uid = ... AND session = ...

一个缺点是我摆脱了id;如果其他表需要id,则需要进行更改。