2009-10-07 8 views
47

Ich habe drei Tabellen Benutzer zu definieren:MySQL Anzahl der Elemente innerhalb der „in-Klausel“

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 eine mittlere Ebene Benutzer erstellen, die bestimmte Zugriff auf andere Benutzer innerhalb der Anwendung hat. welche Benutzer die im Gebrauch angemeldet, um zu bestimmen zugreifen können, ich bin mit einer Unterabfrage wie folgt aus:

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 ich die Unterabfrage-String in einer Variablen bin zu speichern und dann dynamisch in die äußere Abfrage Einfügen jedes Mal, wenn ich brauche um eine Liste von Benutzern zu ziehen. Nachdem ich das getan hatte, dachte ich: "Es muss besser sein, nur eine Zeichenfolge des tatsächlichen user_id s zu speichern".

Also anstatt zu speichern diese in einer Variablen ...

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

... Ich führe die Abfrage tatsächlich und das Ergebnis wie folgt aus ...

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

Dann, wenn ich brauche eine beleuchtete von Benutzern zu ziehen, dass die angemeldeten Benutzer hat Zugriff auf, kann ich so mit:

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

Und schließlich die Fragen:

Wie viele Artikel können Sie in einem MySQL IN CLAUSE verwenden? Speichern der tatsächlichen IDs anstelle der Sub-SQL-Anweisung muss schneller für die Durchführung dieser äußeren Abfrage jedes Mal sein, nicht wahr?

Antwort

33

Ab einer bestimmten Anzahl sind die IN Tabellen schneller.

MySQL hat in seinem Code etwas, das einen Bereich über eine große Anzahl von konstanten Werten langsamer als tut das gleiche in einer verschachtelten Schleife macht das Bauen.

Lesen Sie diesen Artikel in meinem Blog für Leistungsdetails:

+0

Hey Quassnoi: Es scheint eine Menge Uneinigkeit über Ihre Leistungstests und Ihre Behauptung, dass eine temporäre Tabelle besser ist. Ich denke du magst hier falsch liegen. – IcedDante

+1

@IcedDante: Es gibt Skripte, um alles zu reproduzieren, worüber ich im Blogpost geschrieben habe. Sie können Ihren eigenen Blogpost mit Ihren eigenen Skripten schreiben und mir zeigen, wie falsch ich bin. Ansonsten sind Gespräche wie diese nur heiße Luft. – Quassnoi

+0

Ich weiß, dass diese Frage alt ist, aber Ihre Antwort hat die echte Frage nicht beantwortet: "Wie viele Artikel können Sie in einer MySQL IN CLAUSE verwenden?" – Gusman

9

Wie in Quassnoi Antwort angedeutet, ein stößt auf andere praktische Überlegungen, vor eine mögliche Begrenzung trifft verhängt durch eine gegebene MySql Version Implementierung (*). Wenn die Anzahl der Admin-Benutzer (oder anderer Kriterien, die ein IN-Konstrukt benötigen) wächst, sollte man daher nach Alternativen zu einem Literal "IN" suchen, wie etwa die Verwendung von temporären (oder sogar permanenten) Tabellen.

Da Sie eine besondere Behandlung der Kriterien "admin user" in Betracht ziehen, möchte ich aus Performancegründen einen Kommentar und einen Vorschlag anbieten.

Kommentar: Könnte dies eine vorzeitige Optimierung sein?
Ich bin mir der Besonderheiten dieser Datenbank, ihres Volumens, ihrer Komplexität usw. nicht bewusst. Und, ja, ich bin mir bewusst, dass die Performance dem EAV-Format (Entity-Attribute-Value) Tribut zollt, aber ich bin Denken Sie daran, dass selbst für erfolgreiche Unternehmen die Konten-Datenbank selten mehr als 10.000 Benutzer zählt.Selbst bei sehr vielen Attributen pro Benutzer sehen wir uns immer noch eine relativ kleine EAV-Tabelle an, die diese Art der Optimierung möglicherweise nicht benötigt. (Auf der anderen Seite können einige andere Optimierungstricks in anderen Bereichen willkommen sein).
Darüber hinaus beinhalten typische Anwendungsfälle relativ wenige Abfragen in die Kontendatenbank relativ zu anderen Abfragen, und dies ist daher ein weiterer Grund, jegliche nicht triviale Leistungsbeurteilung für die kontenbezogenen Funktionen der Anwendung aufzuheben.

Vorschlag: Vielleicht „re-normalisierte Attribute“ verwendet
Für Attribute, die vereinzelten bewertet werden, insbesondere, wenn sie kurz sind, können sie (oder dupliziert) in der Entity-Tabelle (‚USER‘ bewegt werden Tabelle in diesem Fall). Dies führt zu der Zeit, zu der Elemente eingefügt oder aktualisiert werden, ein wenig Logik ein, aber das gleiche gilt für viele Joins (oder Unterabfragen) und bietet auch Möglichkeiten, Indizes mit mehreren Feldern in Betracht zu ziehen, um die häufigsten Anwendungsfälle zu unterstützen.

(*) Gibt es ein Limit?
Ich habe nicht über eine solche Grenze gelesen; Ich weiß, dass Oracle irgendwann ein Limit von 1.000 hat, 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 man jemals auf diesen stolpert, hat er/sie andere Probleme ... ;-)

4

MySQL's IN-Klausel selbst hat keine solche Grenze. Ich habe mit 8000 Elementen versucht, es funktioniert gut für mich. Stack-Überlauf-Fehler könnte erklärt der variabel sein,

117

Vom manual:

Die Anzahl der Werte in der IN Liste wird nur durch den max_allowed_packet Wert begrenzt.

+10

Ein Beispiel für die Standardeinstellung ist 'max_allowed_packet | 1048576' (1 MB) – icvg

+7

+1 für die Beantwortung der Frage. Vielen Dank. – Bryan

+1

[Der Standardwert von max_allowed_packet ist 4MB] (http://dev.mysql.com/doc/refman/5.7/en/server-variables.html#sysvar_max_allowed_packet) –

Verwandte Themen