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_id
s 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- IN
Klausel 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?
Aus dem Handbuch :
Die Anzahl der Werte in der
IN
Liste ist nur durch denmax_allowed_packet
Wert begrenzt.quelle
max_allowed_packet | 1048576
(1 MB)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 ... ;-)
quelle
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.
quelle
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 sehenEXPLAIN
.quelle