web-dev-qa-db-ja.com

認証のために「ユーザー」テーブルを分割することは良い考えですか?

私のサイトにユーザーテーブルがあり、テーブルに約200万から300万のユーザー(レコード)がいるとします。

ログインプロセスを高速化するために、1つは情報用に、もう1つはログイン用に、ユーザーテーブルを分割することをお勧めします。

次のようなクエリを1つのテーブルから実行できる場合:

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

それを分割する必要はありますか?これは私のサイトのログインプロセスをスピードアップしますか?

8
ALH

IMHO物理的に分割する必要はありません。それでも、それをキャッシュしておくといいでしょう。

usersテーブルがMyISAMストレージエンジンを使用している場合、すばらしい利点があります。

MyISAMはインデックスをキャッシュするだけなので、2つのことを行うことができます

  • usersテーブルのみのMyISAMインデックスをロードするためだけにカスタムキーキャッシュを作成できます
  • ユーザー名とパスワードにインデックスを付けて、クエリにそのカスタムキーキャッシュのみをヒットさせることができます

次のインデックスがusersに存在することを確認してください

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

2つのインデックスには2つの主な理由があります。

インデックス#1の理由

インデックスusername_ndxは、ユーザー名が複数のパスワードを持つことを防ぎ、同じ名前の複数のユーザーを防ぐ

インデックス#2の理由

インデックスusername_password_ndxcovering index を提供します。したがって、クエリは、テーブルをチェックするのではなく、カスタム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;

これらの3行をファイル/var/lib/mysql/startup.sqlに配置する必要があります

これを/etc/my.cnfに追加します

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

これは、mysqlが起動するたびにキャッシュをロードします

試してみる !!!

UPDATE 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';

UPDATE 2011-12-30 23:21 EDT

これは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を再起動します(1回限り)。

10
RolandoMySQLDBA

数百万行のテーブルを分割する必要はありません。パフォーマンスのチューニングは、インデックスを介して行う必要があります。 MySpaceでは、1つのテーブルに数億のアカウントがリストされており、そのテーブルでのパフォーマンスは問題ありませんでした。 (私はMySpaceのDBAでしたが、使用量が最も多かったです。)その場合のテーブルの幅はおそらく80〜90バイト(おそらくもう少し)でした。

5
mrdenny

実際に200万人のユーザーがいますか?すでにこの問題が発生しているか、発生することが確実でない限り、事前に最適化しています。ログインフィールドとパスワードフィールドに複合インデックスを追加し、それで完了します。実際に解決する問題があることがわかっている場合を除いて、最適化しないでください。あなたが解決すべきより大きな問題があると私は確信しています。

3
Aaron Brown

Mysql 5.1以降を使用している場合は、 partitioning テーブルを試すことができます。
ログインプロセスを高速化するかどうかについてのあなたの質問のように、それは残りのログイン手順がどのように見えるかに依存します(たとえば、クエリが0.05秒かかり、残りのコードが20秒かかる場合、むしろルーチン全体を考え直してください...)。
また、パーティションの使用に関係なく、RolandoMySQLDBAが指摘したように、インデックスを追加することを忘れないでください。

2
a1ex07