74

ユーザーを定義するための3つのテーブルがあります。

USER: user_id (int), username (varchar)
USER_METADATA_FIELD: user_metadata_field_id (int), field_name (varchar)
USER_METADATA: user_metadata_field_id (int), user_id (int), field_value (varchar)

アプリケーション内の他のユーザーに特定のアクセス権を持つ中間層ユーザーを作成したいと思います。ログインしたユーザーがアクセスできるユーザーを判別するために、次のようなサブクエリを使用しています。

SELECT user_id FROM user WHERE user_id 
     IN (SELECT user_id 
         FROM user_metadata 
         WHERE user_metadata_field_id = 1 AND field_value = 'foo')

現在、サブクエリ文字列を変数に格納し、ユーザーのリストを取得する必要があるたびに、それを外部クエリに動的に挿入しています。これを行った後、「実際のsの文字列を格納する方がよい」と思いましたuser_id

したがって、これを変数に格納する代わりに...

$subSql = "SELECT user_id FROM user_metadata WHERE user_metadata_field_id = 1 AND field_value = 'foo'";

...実際にクエリを実行して結果を次のように保存します...

$subSql = "12, 56, 89, 100, 1234, 890";

次に、ログインしているユーザーがアクセスできるユーザーを取得する必要がある場合は、次の方法で実行できます。

$sql = "SELECT user_id FROM user WHERE user_id IN ($subSql)";

そして最後に質問:

MySQL INCLAUSEではいくつのアイテムを使用できますか?サブSQLステートメントの代わりに実際のIDを保存することは、毎回その外部クエリを実行するために高速である必要がありますよね?

4

5 に答える 5

161

マニュアルから:

リスト内の値の数は、値INによってのみ制限されmax_allowed_packetます。

于 2012-01-10T19:02:08.577 に答える
36

特定の数から始めて、INテーブルはより速くなります。

MySQLコード内に何かがあり、ネストされたループで同じことを行うよりも、多数の定数値の範囲を構築するのが遅くなります。

パフォーマンスの詳細については、私のブログのこの記事を参照してください。

于 2009-10-07T15:42:50.423 に答える
11

Quassnoiの応答で示唆されているように、特定のMySqlバージョンの実装(*)によって課せられる可能性のある制限に達する前に、他の実際的な考慮事項に遭遇します。したがって、管理ユーザー(またはIN構造を必要とする可能性のある他の基準)の数が増えるにつれて、一時的(または永続的)テーブルの使用など、リテラル「IN」の代替を使用するように努める必要があります。

「adminuser」基準の特別な取り扱いを検討しているので、パフォーマンスの目的で、コメントと提案を提供したいと思います。

コメント:これは時期尚早の最適化の場合でしょうか?
私はこのデータベースの詳細、そのボリューム、複雑さなどを知りません。そして、はい、EAV(Entity-Attribute-Value)形式に支払われるパフォーマンスへの賛辞を知っていますが、私はそれを考えています成功したビジネスであっても、アカウントデータベースが10,000ユーザーを超えることはめったにありません。したがって、ユーザーごとに非常に多くの属性がある場合でも、比較的小さなEAVテーブルを確認しているため、このタイプの最適化は必要ない場合があります。(一方、他のいくつかの最適化のトリックは他の分野で歓迎されるかもしれません)。
さらに、一般的なユースケースでは、他のクエリと比較して、アカウントデータベースへの問い合わせが比較的少ないため、アプリケーションのアカウント関連機能のパフォーマンスに関する重要な考慮事項を延期するもう1つの理由があります。

提案: 「再正規化された属性」を使用する
可能性があります。単一値の属性、特に短い属性の場合は、エンティティテーブル(この場合は「USER」テーブル)で移動(または複製)できます。これにより、アイテムが挿入または更新されるときに少しロジックが導入されますが、これは多くの結合(またはサブクエリ)と同じであり、最も一般的なユースケースをサポートするためにマルチフィールドインデックスを検討する機会も提供します。

(*)制限はありますか?
私はそのような制限について読んだことがありません。Oracleにはある時点で1,000の制限があることを知っていますが、MSSQLにはありません。もちろん、すべてのサーバーにはSQLステートメントの全体の長さに基づいた制限がありますが、これは非常に大きな数です。誰かがそれに遭遇した場合、彼/彼女は他の問題を抱えています... ;-)

于 2009-10-07T16:16:04.533 に答える
7

MySQLのIN句自体にはそのような制限はありません。私は8000個の要素でそれがうまく機能することを試しました。スタックオーバーフローエラーは、変数が宣言されている可能性があります。

于 2011-04-20T07:31:37.587 に答える
0

句内に1000を超える値がある場合、IN()MariaDBはパフォーマンス向上のために一時テーブルを自動的に作成するようです。これは、を使用して確認できますEXPLAIN

于 2020-01-30T10:34:55.600 に答える