出于身份验证目的而拆分“用户”表是一个好主意吗?


8

假设我的站点中有一个用户表,该表中大约有2-3百万个用户(记录)。

为了加快我的登录过程,这是拆分用户表的好方法,一个用户表用于提供信息,另一个用于用户登录。

如果我们可以从一个表中运行类似于以下查询的查询:

select username,password from users where username=`test` AND password=****

是否有必要将其拆分,这会加快我的网站的登录过程吗?


1
将此添加为注释,因为它不能直接回答您的问题。也许这是您在示例查询之外所做的事情,但是将实际密码存储在数据库中是非常不好的做法。您想将它们存储为一个,然后查询,例如:password_hash = hash($ userEnteredPassword)
atxdba 2011年

@atxdba我实际上对它们进行了哈希处理,但是在这里我仅举了一个例子。
ALH

Answers:


10

恕我直言,您无需将其物理拆分。但是,缓存它会很好。

如果该users表使用MyISAM存储引擎,则将具有很好的优势。

由于MyISAM仅缓存索引,因此您可以做两件事

  • 您可以创建一个自定义键缓存,仅用于加载users表的MyISAM索引
  • 您可以为用户名和密码建立索引,以强制查询仅击中该自定义键缓存

确保以下索引存在 users

ALTER TABLE users ADD UNIQUE INDEX username_ndx (username);
ALTER TABLE users ADD UNIQUE INDEX username_password_ndx (username,password);

这两个索引有两个主要原因(2)

索引#1的原因

该索引username_ndx可防止一个用户名具有多个密码,并防止多个具有相同名称的用户

索引#2的原因

该索引username_password_ndx提供覆盖索引。因此,您的查询将仅在自定义MyISAM缓存中查找用户名和密码,而不是检查表。

有关覆盖索引原理的更多链接

下一步是实际创建该自定义密钥缓存。以下是用于创建8MB密钥缓存并加载该专用密钥缓存的命令(示例:如果表为mydb.users):

SET GLOBAL authentication_cache.key_buffer_size = 1024 * 1024 * 8;
CACHE INDEX mydb.users IN authentication_cache;
LOAD INDEX INTO CACHE mydb.users;

您应该将这三行放在文件/var/lib/mysql/startup.sql中

将此添加到/etc/my.cnf

[mysqld]
init-file=/var/lib/mysql/startup.sql

这将在每次启动mysql时加载缓存

试试看 !!!

更新2011-12-30 17:25 EDT

如果您想获得确切的大小来设置缓存,请使用以下查询:

SELECT CONCAT('1024 * 1024 * ',ROUND(index_length/power(1024,2))) RecommendedCacheSize
FROM information_schema.tables WHERE table_name='users';

更新美国东部时间2011-12-30 23:21

这是一个基于InnoDB的方法

您仍然需要索引

ALTER TABLE users ADD UNIQUE INDEX username_ndx (username);
ALTER TABLE users ADD UNIQUE INDEX username_password_ndx (username,password);

您必须确保InnoDB缓冲池具有可用的用户名和密码。您可能必须诉诸于在mysql启动时进行完整的索引扫描:

步骤1)创建ReadUserPass.sql

echo "select username,password from users;" > /var/lib/mysql/ReadUserPass.sql

第2步)将该脚本添加到/etc/my.cnf

[mysqld]
init-file=/var/lib/mysql/ReadUserPass.sql

步骤3)执行以下操作之一

  • $ service mysql restart
  • mysql> source /var/lib/mysql/ReadUserPass.sql

因为这两个列(用户名和密码)都位于中username_password_ndx,所以构成该索引的所有索引页都被重新加载到InnoDB缓冲池中。这是必要的,因为有可能冲走索引页。为了最大程度地减少这种情况,请增加缓冲池大小并重新启动mysql(一次)。


其实我使用的是InnoDB存储引擎,但我认为它可以使用缓存过程,不是@RolandoMySQLDBA吗?
ALH

否。我回答的步骤仅是MyISAM。
RolandoMySQLDBA 2011年

如果该users表涉及事务,那么我需要仅基于InnoDB提交另一个答案。
RolandoMySQLDBA 2011年

抱歉,我没有提到,我不知道他们会有不同的方法!
ALH

我基于MyISAM进行了回答,因为我希望将用户表缓存在其自己的键缓冲区中。
RolandoMySQLDBA 2011年

5

无需拆分几百万行的表。性能调整应该通过索引来完成。MySpace在一个表中列出了数亿个帐户,该表的性能很好。(在使用它们时,我曾是MySpace的DBA。)在这种情况下,表的宽度可能为80-90字节(可能更多)。


嗯,RAM大小如何?
Chibueze Opata

3

您实际上有200万用户吗?除非您已经遇到此问题或确定会出现问题,否则您将提前进行优化。在登录名和密码字段上添加复合索引,并完成此操作。除非您知道自己确实有问题要解决,否则不要进行优化。我敢肯定您还有更大的问题要解决。


1
“您确定我有更大的问题要解决”是什么意思?
ALH 2012年

1
当我们知道在不久的将来会遇到很多问题时,解决问题没有任何意义。当表中有很多数据时,这种故障排除非常令人头疼!-1为您。
ALH 2012年

2
我的观点是双重的……在您必须进行优化之前不要进行优化,而且200万条记录不是很多。索引会很多。
亚伦·布朗

2

如果使用Mysql 5.1和更高版本,则可以尝试对表进行分区
关于您是否会加快登录过程的问题,这取决于其余登录过程的外观(例如,如果您的查询现在需要0.05秒,而其余代码需要20秒,我宁愿重新考虑整个程序...)。
另外,无论使用分区如何,都不要忘记像RolandoMySQLDBA所指出的那样添加索引。


在优化之前确定性能问题的真正原因的好机会。通常不是我们认为的那样。循证调整是必经之路!
Stuart Woodward
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.