对用户表进行分区

时间:2013-01-07 22:38:59

标签: mysql partitioning

我有一个包含所有系统用户的表。随着时间的推移,一些用户帐户在此表中最终处于休眠和未使用状态。

如果我有大量用户,最好按日期(上次登录日期)对表进行分区,然后根据日期查询用户。例如:您登录并更新了lastlogondate,这是分区使用的内容。

问题:这是否意味着所有当前用户都会在第一个分区中说出他们的日期戳是最新的。这可能是将当前活动用户池保留在一个分区中的好方法,并且取决于上一个活动日期,重新设置的绝对帐户将最终驻留在其他分区中。 (注意:如果用户再次登录,他们将再次激活。)

这是加快查询速度的好方法吗?

1 个答案:

答案 0 :(得分:3)

不,我不会使用这种分区方法。

要从MySQL分区修剪中受益,您的查询必须引用分区键的列。因此,对于您提议的分区方案可以提供任何好处,所有您的用户查询需要引用last_login列,并且您需要不断更新与last_login列进行比较的值:

SELECT ... FROM users WHERE user_name = 'Adam' AND last_login >= '2013-01-01'
-- remember to change this to '2013-02-01' by next month

如果没有搜索特定last_login的术语,查询就必须扫描所有分区。

我也担心“分区流失”,即行频繁地从一个分区移动到另一个分区。

还要记得在MySQL中,分区列必须是表中每个主键或唯一键的一部分。因此,使用last_login作为分区键需要您定义表:

CREATE TABLE Users (
  user_name VARCHAR(12) NOT NULL,
  last_login DATETIME NOT NULL,
  ...
  PRIMARY KEY (user_name, last_login)
);

这会打开另一个用户创建帐户“Adam”的可能数据异常,只要他们具有不同的上次登录时间。两个帐户可以在无限长的时间内存在于同一个表中,直到两个Adams恰好在同一时间登录。然后,由于主键违规,可能会拒绝登录。这将是一个非常令人费解的理由被拒绝登录。

稍微好一点的分区方案是:

CREATE TABLE Users (
  user_name VARCHAR(12) NOT NULL,
  last_login DATETIME NOT NULL,
  is_archived TINYINT(1) NOT NULL DEFAULT 0,
  ...
  PRIMARY KEY (user_name, is_archived)
) PARTITION BY HASH(is_archived) PARTITIONS 2;

目的是定期运行作业以手动归档用户:

UPDATE Users SET is_archived=1 WHERE last_login < CURDATE() - INTERVAL 30 DAY;

这解决了分区流失问题和分区创建杂务问题。它仍然可能允许存在多个“Adam”,但是如果你小心地控制从一个分区到另一个分区移动一行的实例,那应该是较低的风险。

您仍然需要在查询中引用分区键,但您要比较的值将是固定的:

SELECT ... FROM users WHERE user_name = 'Adam' AND is_archived = 0;