MySQL分区和唯一密钥

MySQL分区和唯一密钥,mysql,partitioning,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 NUL

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

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”进行分区,因为它主要用于“select”查询,因此可以有效地执行修剪

然而,问题是我们维护(uid,session)的唯一索引,分区要求参与的列成为唯一索引的一部分。现在在本例中,(id、uid、session)的唯一索引没有意义(将始终是唯一的)


是否仍然可以在不手动检查(uid、会话)的情况下绕过此问题

假定您唯一的
uid,sessionkey
索引为您强制执行一些业务规则

您是否依赖DBMS强制执行该规则?您是否使用
INSERT。。。。在重复的密钥更新…
语句中,或者使用错误处理程序或类似的东西来处理此唯一性?还是只是为了更好的衡量

如果依赖该唯一索引,
id
上对该表进行分区将不起作用。
Fugeddaboudit

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

40M行表通常不够大,不足以作为分区的好候选。如果您有性能问题,您应该研究改进索引

编辑:如果你有现代化的硬件(多TB的存储,大量的RAM)和精心选择的索引,分区(我相信)会带来更多的麻烦。对于少于10*9行的表来说,这无疑是一个很大的麻烦。当自动递增的
id
值必须是
BIGINT
而不是
INT
数据类型(因为INT.MaxValue不够大)时,分区就开始值得考虑了

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

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

  • 不要使用分区。它不会加快这种桌子的速度
  • 我还没有看到通过散列来加速系统的
  • 主键上进行分区几乎没有任何用处
  • 一般来说,当你有一个非常好的“自然”PK--
    (uid,session)
    时,不要有一个
    自动增量
    id。还是应该是
    (toke n)
  • 不要将一个索引作为另一个索引的第一部分:
    (uid)
    是冗余的,因为
    (uid,session)
  • 如果您希望使用表情符号或中文,请考虑使用utf8mb4。另一方面,如果
    token
    是base64,则将其设置为
    ascii
    或其他类型
因此,我认为这会更好(更小、更快等):

你用哪一个来搜索

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

一个缺点是我去掉了
id
;如果其他表需要
id
,则需要在那里进行更改。

您被拧死了。您必须分别为uid和会话编制索引,从而使它们不唯一。我不确定在你的情况下,分开是正确的方式。“超过几百万行”并没有那么多,也不需要我参加。如果您进行分区,还有另一个缺点:mysql分区上没有“全局索引”功能……因此,您的分区充当单独的表。这意味着,如果你想搜索一个特定的uid(这应该发生,因为你在该列上有单独的索引),mysql将必须检查所有分区的所有索引以返回结果,这可能会像今天这样影响性能。我们不需要搜索uid,我们只需要从令牌中找到uid。正如我提到的,id用于select。大约有4000万行需要分区。您是否考虑分区,因为这样做似乎是正确的?或者针对某个特定的问题?当您有唯一的键时,每个
插入
更新
操作也是一个搜索操作。谢谢,请您详细说明“40M行表通常不够大,不足以作为分区的良好候选对象”。我认为这种大小确实可以从分区中受益。但如果不是这样的话,那么当您想对表进行分区时,理想的大小是多少呢。这是六个摩尔定律的周期。在每18个月的周期中,磁盘(和SSD)存储的可用大小都会以相同的成本几乎翻一番。
WHERE token = ...
WHERE uid = ... AND session = ...