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


8

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

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

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

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

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


1
これはコメントに対する直接の回答ではないため、コメントとして追加します。たぶんこれはサンプルクエリの範囲外ですが、実際のパスワードをデータベースに保存することは非常に悪い習慣です。それらをhasとして保存し、where password_hash = hash($ userEnteredPassword)のようにクエリを実行したい
atxdba

@atxdba実際にハッシュ化しましたが、ここでは例を挙げました。
ALH、2011

回答:


10

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_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;

これらの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回限り)。


実際、私はInnoDBストレージエンジンを使用していますが、キャッシュプロセスはそれで問題ないと思います。@ RolandoMySQLDBAではありませんか?
ALH、2011

いいえ。私の回答の手順はMyISAMのみです。
RolandoMySQLDBA 2011

usersテーブルがトランザクションに関係している場合、InnoDBのみに基づいて別の回答を提出する必要があります。
RolandoMySQLDBA 2011

申し訳ありませんが、そのことについては触れませんでしたが、彼らが異なるアプローチをとることを知りませんでした!
ALH、2011

MyISAMに基づいて答えたのは、usersテーブルを独自のキーバッファーにキャッシュしたかったからです。
RolandoMySQLDBA 2011

5

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


えっと、RAMのサイズはいかがでしたか?
Chibueze Opata 2017

3

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


1
「私には解決すべきより大きな問題があると確信している」とはどういう意味ですか?
ALH、2012年

1
近い将来に多くの問題が発生することがわかっている場合、問題を解決することは意味がありません。テーブルに大量のデータがある場合、このトラブルシューティングは頭痛の種です!-1。
ALH、2012年

2
私のポイントは2つあります...する必要がある前に最適化しないでください&200万レコードはあまり多くありません。インデックスはたくさんあります。
アーロンブラウン

2

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


最適化する前に、パフォーマンスの問題の実際の原因を特定することをお勧めします。多くの場合、私たちがそう思っている場所とは異なります。根拠に基づいたチューニングが進むべき道です!
スチュアートウッドワード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.