MYSQL OR vs IN Leistung

180

Ich frage mich, ob es hinsichtlich der Leistung einen Unterschied zwischen den folgenden gibt

SELECT ... FROM ... WHERE someFIELD IN(1,2,3,4)

SELECT ... FROM ... WHERE someFIELD between  0 AND 5

SELECT ... FROM ... WHERE someFIELD = 1 OR someFIELD = 2 OR someFIELD = 3 ... 

oder wird MySQL das SQL auf die gleiche Weise optimieren, wie Compiler den Code optimieren?

BEARBEITEN: Die AND's in OR' s wurden aus dem in den Kommentaren angegebenen Grund geändert .

Scott
quelle
Ich recherchiere auch diese Sache, aber im Gegensatz zu einigen Aussagen, dass IN in eine Reihe von s I could say that it can also be converted to UNIONORs konvertiert wird, die zum Ersetzen von ORs zur Optimierung der Abfrage empfohlen wird.
Jānis Gruzis

Antworten:

249

Ich musste das sicher wissen, also habe ich beide Methoden verglichen. Ich fand immer INwieder viel schneller als mit OR.

Glauben Sie nicht Menschen, die ihre "Meinung" abgeben. In der Wissenschaft dreht sich alles um Tests und Beweise.

Ich habe eine 1000-fache Schleife der entsprechenden Abfragen ausgeführt (aus Gründen der Konsistenz habe ich verwendet sql_no_cache):

IN: 2.34969592094s

OR: 5.83781504631s

Update:
(Ich habe nicht den Quellcode für den ursprünglichen Test, wie vor 6 Jahren, obwohl er ein Ergebnis im gleichen Bereich wie dieser Test zurückgibt.)

Um einen Beispielcode zum Testen anzufordern, ist hier der einfachste Anwendungsfall. Wenn Sie zur Vereinfachung der Syntax Eloquent verwenden, wird das unformatierte SQL-Äquivalent dasselbe ausgeführt.

$t = microtime(true); 
for($i=0; $i<10000; $i++):
$q = DB::table('users')->where('id',1)
    ->orWhere('id',2)
    ->orWhere('id',3)
    ->orWhere('id',4)
    ->orWhere('id',5)
    ->orWhere('id',6)
    ->orWhere('id',7)
    ->orWhere('id',8)
    ->orWhere('id',9)
    ->orWhere('id',10)
    ->orWhere('id',11)
    ->orWhere('id',12)
    ->orWhere('id',13)
    ->orWhere('id',14)
    ->orWhere('id',15)
    ->orWhere('id',16)
    ->orWhere('id',17)
    ->orWhere('id',18)
    ->orWhere('id',19)
    ->orWhere('id',20)->get();
endfor;
$t2 = microtime(true); 
echo $t."\n".$t2."\n".($t2-$t)."\n";

1482080514.3635
1482080517.3713
3.0078368186951

$t = microtime(true); 
for($i=0; $i<10000; $i++): 
$q = DB::table('users')->whereIn('id',[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])->get(); 
endfor; 
$t2 = microtime(true); 
echo $t."\n".$t2."\n".($t2-$t)."\n";

1482080534.0185
1482080536.178
2.1595389842987

Cyril
quelle
21
Welche Indizes wurden in diesen Tests verwendet?
Eggyal
5
Ich habe auch Abfragen optimiert und festgestellt, dass die INAussage etwa 30% schneller war als eine OR.
Timo002
12
Do not believe people who give their "opinion"Sie haben 100% Recht, Stack Overflow ist leider voll davon
elipoultorak
7
Leistungsgrund (unter Angabe von MariaDB-Dokumenten (ein neuer freier MySQL-Zweig)): => Wenn Ihre Spalte eine Ganzzahl ist, übergeben Sie Ganzzahlen auch an ...Returns 1 if expr is equal to any of the values in the IN list, else returns 0. If all values are constants, they are evaluated according to the type of expr and sorted. The search for the item then is done using a binary search. This means IN is very quick if the IN value list consists entirely of constants . Otherwise, type conversion takes place according to the rules described at Type Conversion, but applied to all the arguments.IN
jave.web
10
Als Folge von " Glauben Sie nicht Menschen, die ihre" Meinung " abgeben " : Die Angabe von Leistungsdaten ohne Berücksichtigung der Skripte, Tabellen und Indizes, die zur Ermittlung dieser Zahlen verwendet wurden, macht sie nicht überprüfbar. Insofern sind die Zahlen so gut wie eine "Meinung".
Desillusioniert
67

Ich habe auch einen Test für zukünftige Googler gemacht. Die Gesamtzahl der zurückgegebenen Ergebnisse beträgt 7264 von 10000

SELECT * FROM item WHERE id = 1 OR id = 2 ... id = 10000

Diese Abfrage dauerte 0.1239Sekunden

SELECT * FROM item WHERE id IN (1,2,3,...10000)

Diese Abfrage dauerte 0.0433Sekunden

IN ist 3 mal schneller als OR

Ergec
quelle
15
Welche MySQL-Engine war das und haben Sie MySQL-Puffer und OS-Datei-Caches zwischen den beiden Abfragen gelöscht?
dabest1
2
Ihr Test ist ein enger Anwendungsfall. Die Abfrage gibt 72% der Daten zurück und profitiert wahrscheinlich nicht von Indizes.
Desillusioniert
Ich wette, die meiste Zeit hat die Abfrage verbraucht, analysiert und geplant. Das ist sicherlich eine Überlegung: Wenn Sie 10.000 ODER-Anweisungen haben, werden Sie viel redundanten Text haben, der ihn nur ausdrückt OR: Verwenden Sie am besten den kompaktesten Ausdruck, der möglich ist.
Bischof
17

Die akzeptierte Antwort erklärt nicht den Grund.

Nachfolgend finden Sie Zitate aus High Performance MySQL, 3. Ausgabe.

In vielen Datenbankservern ist IN () nur ein Synonym für mehrere ODER-Klauseln, da beide logisch äquivalent sind. Nicht so in MySQL, das die Werte in der IN () -Liste sortiert und eine schnelle binäre Suche verwendet, um festzustellen, ob sich ein Wert in der Liste befindet. Dies ist O (Log n) in der Größe der Liste, während eine äquivalente Reihe von OR-Klauseln O (n) in der Größe der Liste ist (dh viel langsamer für große Listen).

Jacob
quelle
Fantastischer Verweis auf den spezifischen Datenbankgrund. Nett!
Joshua Pinter
Perfekt und auf den Punkt
gaurav9620
16

Ich denke, das ZWISCHEN wird schneller sein, da es umgewandelt werden sollte in:

Field >= 0 AND Field <= 5

Nach meinem Verständnis wird ein IN ohnehin in eine Reihe von OR-Anweisungen konvertiert. Der Wert von IN ist die Benutzerfreundlichkeit. (Sie müssen nicht jeden Spaltennamen mehrmals eingeben und können die Verwendung mit vorhandener Logik vereinfachen. Sie müssen sich keine Gedanken über die UND / ODER-Priorität machen, da IN eine Anweisung ist. Mit einer Reihe von ODER-Anweisungen haben Sie um sicherzustellen, dass Sie sie mit Klammern umgeben, um sicherzustellen, dass sie als eine Bedingung bewertet werden.)

Die einzige wirkliche Antwort auf Ihre Frage ist PROFILIEREN SIE IHRE FRAGEN . Dann wissen Sie, was in Ihrer speziellen Situation am besten funktioniert.

Strand
quelle
Statistisch gesehen hat Between die Möglichkeit, den Bereichsindex auszulösen. IN () hat dieses Privileg nicht. Aber ja, Strand ist richtig: Sie MÜSSEN Ihre Anfrage profilieren, um zu wissen, ob und welcher Index verwendet wird. Es ist wirklich schwer vorherzusagen, was der MySQL-Optimierer wählen wird.
Savageman
"Ich verstehe, dass ein IN sowieso in eine Reihe von OR-Anweisungen konvertiert wird." Wo hast du das gelesen? Ich würde erwarten, dass es in eine Hashmap eingefügt wird, um O (1) -Suchen durchzuführen.
Ztyx
INs, die in ORs konvertiert werden, gehen so vor, wie SQLServer damit umgeht (oder zumindest - hat sich möglicherweise geändert, hat es seit Jahren nicht mehr verwendet). Ich konnte keine Beweise dafür finden, dass MySQL dies tut.
RichardAtHome
4
Diese Antwort ist richtig, zwischen wird in "1 <= film_id <= 5" konvertiert. Die anderen beiden Lösungen werden nicht in einen einzigen Bereichszustand gefaltet. Ich habe einen Blog-Beitrag, der dies mit OPTIMIZER TRACE hier demonstriert: tocker.ca/2015/05/25/…
Morgan Tocker
13

Es hängt davon ab, was Sie tun. Wie groß ist der Bereich, was ist der Datentyp (ich weiß, dass Ihr Beispiel einen numerischen Datentyp verwendet, aber Ihre Frage kann auch für viele verschiedene Datentypen gelten).

Dies ist eine Instanz, in der Sie die Abfrage in beide Richtungen schreiben möchten. Bringen Sie es zum Laufen und verwenden Sie EXPLAIN, um die Ausführungsunterschiede herauszufinden.

Ich bin mir sicher, dass es eine konkrete Antwort darauf gibt, aber so würde ich praktisch die Antwort auf meine gegebene Frage herausfinden.

Dies kann hilfreich sein: http://forge.mysql.com/wiki/Top10SQLPerformanceTips

Grüße,
Frank

Frank V.
quelle
2
Dies sollte die ausgewählte Antwort sein.
Jon z
3
Der Link ist veraltet - ich denke, das könnte das Äquivalent sein? wikis.oracle.com/pages/viewpage.action?pageId=27263381 (danke Oracle ;-P)
ilasno
1
Auf der entsprechenden Seite heißt es: "Vermeiden Sie die Verwendung von IN (...) bei der Auswahl indizierter Felder. Dadurch wird die Leistung der SELECT-Abfrage beeinträchtigt." - Irgendeine Idee warum das so ist?
Jorisw
Die URL ist abgelaufen
Steve Jiang
7

Ich denke, eine Erklärung für die Beobachtung von sunseeker ist, dass MySQL die Werte in der IN-Anweisung tatsächlich sortiert, wenn sie alle statische Werte sind und eine binäre Suche verwenden, die effizienter ist als die einfache ODER-Alternative. Ich kann mich nicht erinnern, wo ich das gelesen habe, aber das Ergebnis von sunseeker scheint ein Beweis zu sein.

user658991
quelle
4

Gerade als Sie dachten, es sei sicher ...

Was ist dein Wert eq_range_index_dive_limit? Haben Sie insbesondere mehr oder weniger Artikel in derIN Klausel?

Dies beinhaltet keinen Benchmark, wird aber ein wenig in das Innenleben blicken. Lassen Sie uns ein Tool verwenden, um zu sehen, was los ist - Optimizer Trace.

Die Abfrage: SELECT * FROM canada WHERE id ...

Mit einem ORvon 3 Werten sieht ein Teil der Ablaufverfolgung wie folgt aus:

       "condition_processing": {
          "condition": "WHERE",
          "original_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(multiple equal(296172, `canada`.`id`) or multiple equal(295093, `canada`.`id`) or multiple equal(293626, `canada`.`id`))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "293626 <= id <= 293626",
                      "295093 <= id <= 295093",
                      "296172 <= id <= 296172"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "((`canada`.`id` = 296172) or (`canada`.`id` = 295093) or (`canada`.`id` = 293626))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

Beachten Sie, wie ICP gegeben wird ORs. Dies impliziert, dass dies ORnicht umgesetzt INwird und InnoDB eine Reihe von Auftritten ausführen wird= Tests über ICP durchführen wird. (Ich halte es nicht für sinnvoll, über MyISAM nachzudenken.)

(Dies ist Perconas 5.6.22-71.0-Protokoll; idist ein Sekundärindex.)

Nun zu IN () mit einigen Werten

eq_range_index_dive_limit= 10; Es gibt 8 Werte.

        "condition_processing": {
          "condition": "WHERE",
          "original_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "293626 <= id <= 293626",
                      "295093 <= id <= 295093",
                      "295573 <= id <= 295573",
                      "295588 <= id <= 295588",
                      "295810 <= id <= 295810",
                      "296127 <= id <= 296127",
                      "296172 <= id <= 296172",
                      "297148 <= id <= 297148"
                    ],
                    "index_dives_for_eq_ranges": true,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "(`canada`.`id` in (296172,295093,293626,295573,297148,296127,295588,295810))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

Beachten Sie, dass das INnicht in verwandelt zu sein scheintOR .

Eine Randnotiz: Beachten Sie, dass die konstanten Werte sortiert wurden . Dies kann auf zwei Arten vorteilhaft sein:

  • Wenn Sie weniger herumspringen, kann es zu einem besseren Caching und weniger E / A kommen, um alle Werte zu erreichen.
  • Wenn zwei ähnliche Abfragen von getrennten Verbindungen stammen und sich in Transaktionen befinden, besteht aufgrund überlappender Listen eine bessere Wahrscheinlichkeit, dass eine Verzögerung anstelle eines Deadlocks auftritt.

Schließlich IN () mit vielen Werten

      {
        "condition_processing": {
          "condition": "WHERE",
          "original_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
          "steps": [
            {
              "transformation": "equality_propagation",
              "resulting_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))"
            },

...

              "analyzing_range_alternatives": {
                "range_scan_alternatives": [
                  {
                    "index": "id",
                    "ranges": [
                      "291752 <= id <= 291752",
                      "291839 <= id <= 291839",
                      ...
                      "297196 <= id <= 297196",
                      "297201 <= id <= 297201"
                    ],
                    "index_dives_for_eq_ranges": false,
                    "rows": 111,
                    "chosen": true

...

        "refine_plan": [
          {
            "table": "`canada`",
            "pushed_index_condition": "(`canada`.`id` in (293831,292259,292881,293440,292558,295792,292293,292593,294337,295430,295034,297060,293811,295587,294651,295559,293213,295742,292605,296018,294529,296711,293919,294732,294689,295540,293000,296916,294433,297112,293815,292522,296816,293320,293232,295369,291894,293700,291839,293049,292738,294895,294473,294023,294173,293019,291976,294923,294797,296958,294075,293450,296952,297185,295351,295736,296312,294330,292717,294638,294713,297176,295896,295137,296573,292236,294966,296642,296073,295903,293057,294628,292639,293803,294470,295353,297196,291752,296118,296964,296185,295338,295956,296064,295039,297201,297136,295206,295986,292172,294803,294480,294706,296975,296604,294493,293181,292526,293354,292374,292344,293744,294165,295082,296203,291918,295211,294289,294877,293120,295387))",
            "table_condition_attached": null,
            "access_type": "range"
          }
        ]

Randnotiz: Ich brauchte dies wegen der Sperrigkeit der Spur:

@@global.optimizer_trace_max_mem_size = 32222;
Rick James
quelle
3

ODER wird am langsamsten sein. Ob IN oder ZWISCHEN schneller ist, hängt von Ihren Daten ab, aber ich würde erwarten, dass ZWISCHEN normalerweise schneller ist, da es einfach einen Bereich aus einem Index übernehmen kann (vorausgesetzt, someField ist indiziert).

Greg
quelle
3

Im Folgenden finden Sie Details zu 6 Abfragen mit MySQL 5.6 @SQLFiddle

Zusammenfassend decken die 6 Abfragen unabhängig indizierte Spalten ab und 2 Abfragen wurden pro Datentyp verwendet. Alle Abfragen führten zur Verwendung eines Index, unabhängig davon, ob IN () oder ORs verwendet wurden.

        |   ORs      |   IN()
integer | uses index | uses index
date    | uses index | uses index
varchar | uses index | uses index

Ich wollte wirklich nur Aussagen entlarven, dass OR bedeutet, dass kein Index verwendet werden kann. Das ist nicht wahr. Indizes können in Abfragen mit OR verwendet werden, da die 6 Abfragen in den folgenden Beispielen angezeigt werden.

Es scheint mir auch, dass viele die Tatsache ignoriert haben, dass IN () eine Syntaxverknüpfung für eine Reihe von ORs ist. Im kleinen Maßstab sind die Leistungsunterschiede zwischen der Verwendung von IN () -v- OR extrem (unendlich) gering.

In größerem Maßstab ist IN () zwar bequemer, entspricht aber logischerweise einer Reihe von ODER-Bedingungen. Die Umstände ändern sich für jede Abfrage, daher ist es immer am besten, Ihre Abfrage in Ihren Tabellen zu testen.

Zusammenfassung der 6 Erklärungspläne, alle "Indexbedingung verwenden" (nach rechts scrollen)

  Query               select_type    table    type    possible_keys      key      key_len   ref   rows   filtered           Extra          
                      ------------- --------- ------- --------------- ----------- --------- ----- ------ ---------- ----------------------- 
  Integers using OR   SIMPLE        mytable   range   aNum_idx        aNum_idx    4               10     100.00     Using index condition  
  Integers using IN   SIMPLE        mytable   range   aNum_idx        aNum_idx    4               10     100.00     Using index condition  
  Dates using OR      SIMPLE        mytable   range   aDate_idx       aDate_idx   6               7      100.00     Using index condition  
  Dates using IN      SIMPLE        mytable   range   aDate_idx       aDate_idx   6               7      100.00     Using index condition  
  Varchar using OR    SIMPLE        mytable   range   aName_idx       aName_idx   768             10     100.00     Using index condition  
  Varchar using IN    SIMPLE        mytable   range   aName_idx       aName_idx   768             10     100.00     Using index condition  

SQL Fiddle

MySQL 5.6 Schema Setup :

CREATE TABLE `myTable` (
  `id` mediumint(8) unsigned NOT NULL auto_increment,
  `aName` varchar(255) default NULL,
  `aDate` datetime,
  `aNum`  mediumint(8),
  PRIMARY KEY (`id`)
) AUTO_INCREMENT=1;

ALTER TABLE `myTable` ADD INDEX `aName_idx` (`aName`);
ALTER TABLE `myTable` ADD INDEX `aDate_idx` (`aDate`);
ALTER TABLE `myTable` ADD INDEX `aNum_idx` (`aNum`);

INSERT INTO `myTable` (`aName`,`aDate`)
 VALUES 
 ("Daniel","2017-09-19 01:22:31")
,("Quentin","2017-06-03 01:06:45")
,("Chester","2017-06-14 17:49:36")
,("Lev","2017-08-30 06:27:59")
,("Garrett","2018-10-04 02:40:37")
,("Lane","2017-01-22 17:11:21")
,("Chaim","2017-09-20 11:13:46")
,("Kieran","2018-03-10 18:37:26")
,("Cedric","2017-05-20 16:25:10")
,("Conan","2018-07-10 06:29:39")
,("Rudyard","2017-07-14 00:04:00")
,("Chadwick","2018-08-18 08:54:08")
,("Darius","2018-10-02 06:55:56")
,("Joseph","2017-06-19 13:20:33")
,("Wayne","2017-04-02 23:20:25")
,("Hall","2017-10-13 00:17:24")
,("Craig","2016-12-04 08:15:22")
,("Keane","2018-03-12 04:21:46")
,("Russell","2017-07-14 17:21:58")
,("Seth","2018-07-25 05:51:30")
,("Cole","2018-06-09 15:32:53")
,("Donovan","2017-08-12 05:21:35")
,("Damon","2017-06-27 03:44:19")
,("Brian","2017-02-01 23:35:20")
,("Harper","2017-08-25 04:29:27")
,("Chandler","2017-09-30 23:54:06")
,("Edward","2018-07-30 12:18:07")
,("Curran","2018-05-23 09:31:53")
,("Uriel","2017-05-08 03:31:43")
,("Honorato","2018-04-07 14:57:53")
,("Griffin","2017-01-07 23:35:31")
,("Hasad","2017-05-15 05:32:41")
,("Burke","2017-07-04 01:11:19")
,("Hyatt","2017-03-14 17:12:28")
,("Brenden","2017-10-17 05:16:14")
,("Ryan","2018-10-10 08:07:55")
,("Giacomo","2018-10-06 14:21:21")
,("James","2018-02-06 02:45:59")
,("Colt","2017-10-10 08:11:26")
,("Kermit","2017-09-18 16:57:16")
,("Drake","2018-05-20 22:08:36")
,("Berk","2017-04-16 17:39:32")
,("Alan","2018-09-01 05:33:05")
,("Deacon","2017-04-20 07:03:05")
,("Omar","2018-03-02 15:04:32")
,("Thaddeus","2017-09-19 04:07:54")
,("Troy","2016-12-13 04:24:08")
,("Rogan","2017-11-02 00:03:25")
,("Grant","2017-08-21 01:45:16")
,("Walker","2016-11-26 15:54:52")
,("Clarke","2017-07-20 02:26:56")
,("Clayton","2018-08-16 05:09:29")
,("Denton","2018-08-11 05:26:05")
,("Nicholas","2018-07-19 09:29:55")
,("Hashim","2018-08-10 20:38:06")
,("Todd","2016-10-25 01:01:36")
,("Xenos","2017-05-11 22:50:35")
,("Bert","2017-06-17 18:08:21")
,("Oleg","2018-01-03 13:10:32")
,("Hall","2018-06-04 01:53:45")
,("Evan","2017-01-16 01:04:25")
,("Mohammad","2016-11-18 05:42:52")
,("Armand","2016-12-18 06:57:57")
,("Kaseem","2018-06-12 23:09:57")
,("Colin","2017-06-29 05:25:52")
,("Arthur","2016-12-29 04:38:13")
,("Xander","2016-11-14 19:35:32")
,("Dante","2016-12-01 09:01:04")
,("Zahir","2018-02-17 14:44:53")
,("Raymond","2017-03-09 05:33:06")
,("Giacomo","2017-04-17 06:12:52")
,("Fulton","2017-06-04 00:41:57")
,("Chase","2018-01-14 03:03:57")
,("William","2017-05-08 09:44:59")
,("Fuller","2017-03-31 20:35:20")
,("Jarrod","2017-02-15 02:45:29")
,("Nissim","2018-03-11 14:19:25")
,("Chester","2017-11-05 00:14:27")
,("Perry","2017-12-24 11:58:04")
,("Theodore","2017-06-26 12:34:12")
,("Mason","2017-10-02 03:53:49")
,("Brenden","2018-10-08 10:09:47")
,("Jerome","2017-11-05 20:34:25")
,("Keaton","2018-08-18 00:55:56")
,("Tiger","2017-05-21 16:59:07")
,("Benjamin","2018-04-10 14:46:36")
,("John","2018-09-05 18:53:03")
,("Jakeem","2018-10-11 00:17:38")
,("Kenyon","2017-12-18 22:19:29")
,("Ferris","2017-03-29 06:59:13")
,("Hoyt","2017-01-03 03:48:56")
,("Fitzgerald","2017-07-27 11:27:52")
,("Forrest","2017-10-05 23:14:21")
,("Jordan","2017-01-11 03:48:09")
,("Lev","2017-05-25 08:03:39")
,("Chase","2017-06-18 19:09:23")
,("Ryder","2016-12-13 12:50:50")
,("Malik","2017-11-19 15:15:55")
,("Zeph","2018-04-04 11:22:12")
,("Amala","2017-01-29 07:52:17")
;

.

update MyTable
set aNum = id
;

Abfrage 1 :

select 'aNum by OR' q, mytable.*
from mytable
where aNum = 12
OR aNum = 22
OR aNum = 27
OR aNum = 32
OR aNum = 42
OR aNum = 52
OR aNum = 62
OR aNum = 65
OR aNum = 72
OR aNum = 82

Ergebnisse :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| aNum by OR | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| aNum by OR | 22 |  Donovan | 2017-08-12T05:21:35Z |   22 |
| aNum by OR | 27 |   Edward | 2018-07-30T12:18:07Z |   27 |
| aNum by OR | 32 |    Hasad | 2017-05-15T05:32:41Z |   32 |
| aNum by OR | 42 |     Berk | 2017-04-16T17:39:32Z |   42 |
| aNum by OR | 52 |  Clayton | 2018-08-16T05:09:29Z |   52 |
| aNum by OR | 62 | Mohammad | 2016-11-18T05:42:52Z |   62 |
| aNum by OR | 65 |    Colin | 2017-06-29T05:25:52Z |   65 |
| aNum by OR | 72 |   Fulton | 2017-06-04T00:41:57Z |   72 |
| aNum by OR | 82 |  Brenden | 2018-10-08T10:09:47Z |   82 |

Abfrage 2 :

select 'aNum by IN' q, mytable.*
from mytable
where aNum IN (
            12
          , 22
          , 27
          , 32
          , 42
          , 52
          , 62
          , 65
          , 72
          , 82
          )

Ergebnisse :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| aNum by IN | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| aNum by IN | 22 |  Donovan | 2017-08-12T05:21:35Z |   22 |
| aNum by IN | 27 |   Edward | 2018-07-30T12:18:07Z |   27 |
| aNum by IN | 32 |    Hasad | 2017-05-15T05:32:41Z |   32 |
| aNum by IN | 42 |     Berk | 2017-04-16T17:39:32Z |   42 |
| aNum by IN | 52 |  Clayton | 2018-08-16T05:09:29Z |   52 |
| aNum by IN | 62 | Mohammad | 2016-11-18T05:42:52Z |   62 |
| aNum by IN | 65 |    Colin | 2017-06-29T05:25:52Z |   65 |
| aNum by IN | 72 |   Fulton | 2017-06-04T00:41:57Z |   72 |
| aNum by IN | 82 |  Brenden | 2018-10-08T10:09:47Z |   82 |

Abfrage 3 :

select 'adate by OR' q, mytable.*
from mytable
where aDate= str_to_date("2017-02-15 02:45:29",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-03-10 18:37:26",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-05-20 16:25:10",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-07-10 06:29:39",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-07-14 00:04:00",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-08-18 08:54:08",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-10-02 06:55:56",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-04-20 07:03:05",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2018-03-02 15:04:32",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2017-09-19 04:07:54",'%Y-%m-%d %h:%i:%s')
OR aDate = str_to_date("2016-12-13 04:24:08",'%Y-%m-%d %h:%i:%s')

Ergebnisse :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| adate by OR | 47 |     Troy | 2016-12-13T04:24:08Z |   47 |
| adate by OR | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
| adate by OR | 44 |   Deacon | 2017-04-20T07:03:05Z |   44 |
| adate by OR | 46 | Thaddeus | 2017-09-19T04:07:54Z |   46 |
| adate by OR | 10 |    Conan | 2018-07-10T06:29:39Z |   10 |
| adate by OR | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| adate by OR | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |

Abfrage 4 :

select 'adate by IN' q, mytable.*
from mytable
where aDate IN (
          str_to_date("2017-02-15 02:45:29",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-03-10 18:37:26",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-05-20 16:25:10",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-07-10 06:29:39",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-07-14 00:04:00",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-08-18 08:54:08",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-10-02 06:55:56",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-04-20 07:03:05",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2018-03-02 15:04:32",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2017-09-19 04:07:54",'%Y-%m-%d %h:%i:%s')
        , str_to_date("2016-12-13 04:24:08",'%Y-%m-%d %h:%i:%s')
        )

Ergebnisse :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| adate by IN | 47 |     Troy | 2016-12-13T04:24:08Z |   47 |
| adate by IN | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
| adate by IN | 44 |   Deacon | 2017-04-20T07:03:05Z |   44 |
| adate by IN | 46 | Thaddeus | 2017-09-19T04:07:54Z |   46 |
| adate by IN | 10 |    Conan | 2018-07-10T06:29:39Z |   10 |
| adate by IN | 12 | Chadwick | 2018-08-18T08:54:08Z |   12 |
| adate by IN | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |

Abfrage 5 :

select 'name by  OR' q, mytable.*
from mytable
where aname = 'Alan'
OR aname = 'Brian'
OR aname = 'Chandler'
OR aname = 'Darius'
OR aname = 'Evan'
OR aname = 'Ferris'
OR aname = 'Giacomo'
OR aname = 'Hall'
OR aname = 'James'
OR aname = 'Jarrod'

Ergebnisse :

|           q | id |    aName |                aDate | aNum |
|-------------|----|----------|----------------------|------|
| name by  OR | 43 |     Alan | 2018-09-01T05:33:05Z |   43 |
| name by  OR | 24 |    Brian | 2017-02-01T23:35:20Z |   24 |
| name by  OR | 26 | Chandler | 2017-09-30T23:54:06Z |   26 |
| name by  OR | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |
| name by  OR | 61 |     Evan | 2017-01-16T01:04:25Z |   61 |
| name by  OR | 90 |   Ferris | 2017-03-29T06:59:13Z |   90 |
| name by  OR | 37 |  Giacomo | 2018-10-06T14:21:21Z |   37 |
| name by  OR | 71 |  Giacomo | 2017-04-17T06:12:52Z |   71 |
| name by  OR | 16 |     Hall | 2017-10-13T00:17:24Z |   16 |
| name by  OR | 60 |     Hall | 2018-06-04T01:53:45Z |   60 |
| name by  OR | 38 |    James | 2018-02-06T02:45:59Z |   38 |
| name by  OR | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |

Abfrage 6 :

select 'name by IN' q, mytable.*
from mytable
where aname IN (
      'Alan'
     ,'Brian'
     ,'Chandler'
     , 'Darius'
     , 'Evan'
     , 'Ferris'
     , 'Giacomo'
     , 'Hall'
     , 'James'
     , 'Jarrod'
     )

Ergebnisse :

|          q | id |    aName |                aDate | aNum |
|------------|----|----------|----------------------|------|
| name by IN | 43 |     Alan | 2018-09-01T05:33:05Z |   43 |
| name by IN | 24 |    Brian | 2017-02-01T23:35:20Z |   24 |
| name by IN | 26 | Chandler | 2017-09-30T23:54:06Z |   26 |
| name by IN | 13 |   Darius | 2018-10-02T06:55:56Z |   13 |
| name by IN | 61 |     Evan | 2017-01-16T01:04:25Z |   61 |
| name by IN | 90 |   Ferris | 2017-03-29T06:59:13Z |   90 |
| name by IN | 37 |  Giacomo | 2018-10-06T14:21:21Z |   37 |
| name by IN | 71 |  Giacomo | 2017-04-17T06:12:52Z |   71 |
| name by IN | 16 |     Hall | 2017-10-13T00:17:24Z |   16 |
| name by IN | 60 |     Hall | 2018-06-04T01:53:45Z |   60 |
| name by IN | 38 |    James | 2018-02-06T02:45:59Z |   38 |
| name by IN | 76 |   Jarrod | 2017-02-15T02:45:29Z |   76 |
Used_By_Already
quelle
2

Ich wette, sie sind gleich. Sie können einen Test durchführen, indem Sie Folgendes tun:

Durchlaufen Sie das "in (1,2,3,4)" 500 Mal und sehen Sie, wie lange es dauert. Durchlaufen Sie die Version "= 1 oder = 2 oder = 3 ..." 500 Mal und sehen Sie, wie lange sie läuft.

Sie können auch einen Join-Weg versuchen. Wenn someField ein Index ist und Ihre Tabelle groß ist, kann es schneller sein ...

SELECT ... 
    FROM ... 
        INNER JOIN (SELECT 1 as newField UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4) dt ON someFIELD =newField

Ich habe die oben beschriebene Join-Methode auf meinem SQL Server ausprobiert und sie entspricht fast der in (1,2,3,4). Beide führen zu einer Suche nach gruppierten Indizes. Ich bin nicht sicher, wie MySQL damit umgehen wird.

KM.
quelle
2

2018 : IN (...) ist schneller. Aber > = && <= ist noch schneller als IN .

Hier ist mein Benchmark .

böseReiko
quelle
0

Soweit ich weiß, wie der Compiler diese Art von Abfragen optimiert, ist die Verwendung der IN-Klausel effizienter als die Verwendung mehrerer OR-Klauseln. Wenn Sie Werte haben, bei denen die BETWEEN-Klausel verwendet werden kann, ist dies noch effizienter.

Brandon Wood
quelle
0

Ich weiß, solange Sie einen Index für Field haben, wird der ZWISCHEN diesen verwenden, um schnell ein Ende zu finden und dann zum anderen zu gelangen. Dies ist am effizientesten.

Jede Erklärung, die ich gesehen habe, zeigt, dass "IN (...)" und "... OR ..." austauschbar und gleichermaßen (in) effizient sind. Was Sie erwarten würden, da der Optimierer nicht wissen kann, ob sie ein Intervall umfassen oder nicht. Dies entspricht auch einer UNION ALL SELECT für die einzelnen Werte.

dkretz
quelle
0

Wie von anderen erklärt, ist IN in Bezug auf die Abfrageleistung besser gewählt als OR.

Abfragen mit ODER-Bedingung können in den folgenden Fällen länger dauern.

  1. Wird ausgeführt, wenn der MySQL-Optimierer einen anderen Index als effizient auswählt (in falsch positiven Fällen).
  2. Wenn die Anzahl der Datensätze höher ist (wie von Jacob klar angegeben)
Adithya
quelle