web-dev-qa-db-ja.com

「in句」内のMySQLのアイテム数

ユーザーを定義する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')

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

これを変数に保存する代わりに...

$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 IN CLAUSEでいくつのアイテムを使用できますか? sub-sqlステートメントの代わりに実際のIDを格納することは、その外部クエリを毎回実行するためにより速くなる必要がありますよね?

62
Bart

特定の数から開始すると、INテーブルの方が高速です。

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

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

34
Quassnoi

manual から:

INリスト内の値の数は、 max_allowed_packet 値。

151
RedFilter

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

「管理ユーザー」基準の特別な処理を検討しているので、パフォーマンスのために、コメントと提案を提供したいと思います。

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

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

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

11
mjv

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

7
Hidayat