Heim > Datenbank > MySQL-Tutorial > Hauptteil

MySQL vermeidet die Verwendung von OR-Bedingungen für Indexspalten

黄舟
Freigeben: 2017-02-21 10:31:11
Original
1315 Leute haben es durchsucht



Ich habe diesen Verlust schon oft erlitten. Im SQL-Code wurden vor der Entwicklung viele Abfragen mit oder als Where-Bedingung sogar aktualisiert. Hier sind Beispiele, um die Nachteile der Verwendung von oder zu veranschaulichen und wie man sie verbessern kann.

select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and (f_mobile ='1234567891' or f_phone ='1234567891' ) limit 1
Nach dem Login kopieren

Anhand der Abfrageanweisung ist leicht zu erkennen, dass in beiden Feldern f_mobile und f_phone Telefonnummern gespeichert werden können. Die allgemeine Idee besteht darin, eine SQL-Anweisung zu verwenden, um das Problem zu lösen, aber die Menge ist groß der Tabellendaten ist einfach eine Katastrophe :

MySQL vermeidet die Verwendung von OR-Bedingungen für Indexspalten

Es gibt die Indizes idx_id_mobile(f_xxx_id,f_mobile), idx_phone(f_phone), idx_id_email(f_id,f_email) auf t_tbanme1, aber die erklären Das Ergebnis verwendet manchmal den Index idx_id_email. Wenn Sie Glück haben, können Sie idx_id_mobile f_xxx_id

wählen, da Sie für jede Abfrage von MySQL nur einen Index für jede Tabelle auswählen können. Wenn der Index idx_id_mobile verwendet wird und es zufällig ein Datenelement gibt, weil es Limit 1 gibt, dann herzlichen Glückwunsch zum schnellen Erhalten des Ergebnisses. Wenn jedoch keine Daten für f_mobile vorhanden sind, kann das Feld f_phone nur einzeln durchsucht werden die f_id-Bedingung, Scannen von 120.000 Zeilen. or unterscheidet sich von and. Einige Entwickler denken sogar, dass das Hinzufügen von (f_xxx_id,f_mobile,f_phone) perfekt wäre

Die Optimierung von SQL ist also sehr einfach (

Beachten Sie, dass es entsprechende Indizes für f_mobile und f_phone geben muss

),

Methode 1:

(select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_mobile ='1234567891' limit 1 ) UNION ALL 
(select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_phone ='1234567891' limit 1 )
Nach dem Login kopieren

Zwei unabhängige SQLs können den Index verwenden, und jede Abfrage hat ihr eigenes Limit. Wenn beide Ergebnismengen zurückgegeben werden, wählen Sie einfach eine aus. MySQL vermeidet die Verwendung von OR-Bedingungen für Indexspalten

Es gibt eine andere Optimierungsmethode. Wenn diese Art von Abfrage besonders häufig vorkommt (und kein Cache vorhanden ist), ändern Sie sie beispielsweise in eine separate SQL-Ausführung f_mobile, führen Sie dann zuerst sql1 aus und führen Sie dann sql2 aus, nachdem festgestellt wurde, dass es kein Ergebnis gibt. Dies kann die Geschwindigkeit der Datenbankabfrage verringern und es dem Code ermöglichen, mehr Dinge zu verarbeiten

Pseudocode:

Ein komplexeres Szenario. Es ist so einfach wie die Rückgabe eines Datensatzes, Limit 2:

sql1 = select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_mobile ='1234567891' limit 1;
sq1.execute();
if no result sql1:
  sql1 = select f_crm_id from d_dbname1.t_tbname1 where f_xxx_id = 926067 and f_phone ='1234567891' limit 1;
    sql1.execute();
Nach dem Login kopieren
In diesem Fall müssen die Methoden eins und zwei verwendet werden geändert werden, da sowohl f_create_time als auch f_modify_time möglicherweise die Beurteilungsbedingungen erfüllen, sodass doppelte Daten zurückgegeben werden.

Methode 1 muss geändert werden:
select a.f_crm_id from d_dbname1.t_tbname1 as a where (a.f_create_time > from_unixtime('1464397527') or a.f_modify_time > from_unixtime('1464397527') ) limit 0,200
Nach dem Login kopieren

Einige Leute sagen, dass durch die Änderung von UNION ALL in UNION die Duplizierung nicht entfernt wird? Wenn Abfragen häufig erfolgen oder das Limit relativ groß ist, steht die Datenbank immer noch unter Druck, sodass ein Kompromiss erforderlich ist.

In diesem Fall ist Methode 2 besser geeignet, auch in Situationen, in denen eine Bestellung nach Limit erforderlich sein kann. Transformieren Sie den Pseudocode:
(select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_create_time > from_unixtime('1464397527') limit 0,200 ) UNION ALL
(select a.f_crm_id from d_dbname1.t_tbname1 as a where a.f_modify_time > from_unixtime(&#39;1464397527&#39;)and a.f_create_time <= from_unixtime(&#39;1464397527&#39;) limit 0,200)
Nach dem Login kopieren

oder die Bedingungen sind in der Datenbank schwer zu optimieren. Die Logik kann im Code optimiert werden, um die Datenbank nicht zu beeinträchtigen. Dies wird nur berücksichtigt, wenn unter der Bedingung „oder“ kein Index erforderlich ist (und die zu vergleichende Datenmenge gering ist).

Dasselbe Feld oder kann in in geändert werden, z. B. f_id=1 oder f_id=100 -> Informationen zu Effizienzproblemen finden Sie im Artikel Die Effizienzprobleme von or und in in MySQL.

Die oben genannten Optimierungsszenarien sind alle Speicher-Engines im Fall von InnoDB. Sie unterscheiden sich in MyISAM oder Bedingungen, bei denen Sie Indizes verwenden können, um die vollständige Tabelle zu vermeiden.

Das Obige ist der Inhalt von MySQL, um die Verwendung von ODER-Bedingungen in Indexspalten zu vermeiden. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)!


Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage