MySQL Anzahl der Elemente in "in Klausel"

69

Ich habe drei Tabellen, um Benutzer zu definieren:

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)

Ich möchte einen Benutzer der mittleren Ebene erstellen, der bestimmten Zugriff auf andere Benutzer in der Anwendung hat. Um festzustellen, auf welche Benutzer der angemeldete Benutzer zugreifen kann, verwende ich eine Unterabfrage wie die folgende:

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')

Derzeit speichere ich die Unterabfragezeichenfolge in einer Variablen und füge sie dann jedes Mal dynamisch in die äußere Abfrage ein, wenn ich eine Liste von Benutzern abrufen muss. Danach dachte ich: "Es muss besser sein, nur eine Zeichenfolge der tatsächlichen user_ids zu speichern ."

Also anstatt dies in einer Variablen zu speichern ...

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

... Ich führe die Abfrage tatsächlich durch und speichere das Ergebnis so ...

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

Wenn ich dann eine Anzahl von Benutzern abrufen muss, auf die der angemeldete Benutzer Zugriff hat, kann ich dies tun mit:

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

Und zum Schluss die Fragen:

Wie viele Elemente können Sie in einer MySQL- INKlausel verwenden? Das Speichern der tatsächlichen IDs anstelle der Sub-SQL-Anweisung muss schneller sein, damit diese äußere Abfrage jedes Mal ausgeführt werden kann, oder?

Bart
quelle

Antworten:

35

Ab einer bestimmten Anzahl sind die INTabellen schneller.

MySQL Der Code enthält etwas, das das Erstellen eines Bereichs über eine große Anzahl konstanter Werte langsamer macht als das gleiche in einer verschachtelten Schleife.

Weitere Informationen zur Leistung finden Sie in diesem Artikel in meinem Blog:

Quassnoi
quelle
Hey Quassnoi: Es scheint eine Menge Meinungsverschiedenheiten über Ihre Leistungstests und Ihre Behauptung zu geben, dass eine temporäre Tabelle besser ist. Ich denke, Sie können sich hier irren.
IcedDante
3
@IcedDante: Es gibt Skripte, mit denen ich alles reproduzieren kann, worüber ich im Blogbeitrag geschrieben habe. Sie können Ihren eigenen Blog-Beitrag mit Ihren eigenen Skripten schreiben und zeigen, wie falsch ich bin. Ansonsten sind solche Gespräche nur heiße Luft.
Quassnoi
4
Ich weiß, dass diese Frage alt ist, aber Ihre Antwort hat die eigentliche Frage weder beantwortet noch beantwortet: "Wie viele Elemente können Sie in MySQL IN CLAUSE verwenden?"
Gusman
11

Wie in Quassnois Antwort angedeutet, stößt man auf andere praktische Überlegungen, bevor man eine mögliche Grenze erreicht stößt, die durch die Implementierung einer bestimmten MySql-Version (*) vorgegeben ist. Mit zunehmender Anzahl von Administratorbenutzern (oder anderen Kriterien, für die möglicherweise ein IN-Konstrukt erforderlich ist) sollte daher versucht werden, Alternativen zu einem wörtlichen "IN" zu verwenden, z. B. die Verwendung temporärer (oder sogar permanenter) Tabellen.

Da Sie aus Leistungsgründen eine besondere Behandlung der Kriterien für "Administratorbenutzer" in Betracht ziehen, möchte ich einen Kommentar und einen Vorschlag machen.

Kommentar: Könnte dies ein Fall vorzeitiger Optimierung sein? Darüber hinaus umfassen typische Anwendungsfälle relativ wenige Anfragen in der Kontodatenbank im Vergleich zu anderen Abfragen, und dies ist daher ein weiterer Grund, eine nicht triviale Leistungsüberlegung für die kontenbezogenen Funktionen der Anwendung zu verschieben.
Ich kenne die Besonderheiten dieser Datenbank, ihr Volumen, ihre Komplexität usw. nicht. Und ja, ich kenne einige Leistungsmerkmale, die dem EAV-Format (Entity-Attribute-Value) zu zahlen sind, aber ich denke das Selbst für erfolgreiche Unternehmen zählt die Kontodatenbank selten mehr als 10.000 Benutzer. Selbst bei sehr vielen Attributen pro Benutzer sehen wir uns immer noch eine relativ kleine EAV-Tabelle an, für die diese Art der Optimierung möglicherweise nicht erforderlich ist. (Andererseits können einige andere Optimierungstricks in anderen Bereichen willkommen sein).

Vorschlag: Verwenden Sie möglicherweise "normalisierte Attribute"
für Attribute mit einem einzigen Wert, und insbesondere wenn sie kurz sind, können sie in der Entitätstabelle (in diesem Fall 'USER'-Tabelle) verschoben (oder dupliziert) werden. Dies führt ein wenig Logik zum Zeitpunkt des Einfügens oder Aktualisierens von Elementen ein, entspricht jedoch vielen Verknüpfungen (oder Unterabfragen) und bietet auch die Möglichkeit, Indizes mit mehreren Feldern zu berücksichtigen, um die häufigsten Anwendungsfälle zu unterstützen.

(*) Gibt es einen Limt?
Ich habe über eine solche Grenze nicht gelesen. Ich weiß, dass Oracle irgendwann ein Limit von 1.000 hat (hatte), MSSQL nicht. Natürlich haben alle Server ein Limit basierend auf der Gesamtlänge der SQL-Anweisung, aber das ist eine wirklich große Zahl! Wenn jemand jemals darauf stößt, hat er / sie andere Probleme ... ;-)

mjv
quelle
7

Die IN-Klausel von MySQL selbst hat keine solche Begrenzung. Ich habe mit 8000 Elementen versucht, dass es für mich gut funktioniert. Der Stapelüberlauffehler kann von einer deklarierten Variablen sein.

Hidayat
quelle
0

Wenn Sie mehr als 1000 Werte in der IN()Klausel haben, scheint MariaDB automatisch temporäre Tabellen zur Leistungsverbesserung zu erstellen. Sie können dies mit sehen EXPLAIN.

Einsamkeit
quelle