Praktische Begrenzung der Länge der SQL-Abfrage (speziell MySQL)

Ist es besonders schlecht, eine sehr, sehr große SQL-Abfrage mit vielen (möglicherweise redundanten) WHERE-Klauseln zu haben?

Beispiel: Hier ist eine Abfrage, die ich aus meiner Webanwendung generiert habe und bei der alles deaktiviert ist. Dies sollte die größtmögliche Abfrage sein, die dieses Programm generiert:

SELECT * 
FROM 4e_magic_items 
INNER JOIN 4e_magic_item_levels 
  ON 4e_magic_items.id = 4e_magic_item_levels.itemid 
INNER JOIN 4e_monster_sources 
  ON 4e_magic_items.source = 4e_monster_sources.id 
WHERE (itemlevel BETWEEN 1 AND 30)  
  AND source!=16 AND source!=2 AND source!=5 
  AND source!=13 AND source!=15 AND source!=3 
  AND source!=4 AND source!=12 AND source!=7 
  AND source!=14 AND source!=11 AND source!=10 
  AND source!=8 AND source!=1 AND source!=6 
  AND source!=9  AND type!='Arms' AND type!='Feet' 
  AND type!='Hands' AND type!='Head' 
  AND type!='Neck' AND type!='Orb' 
  AND type!='Potion' AND type!='Ring' 
  AND type!='Rod' AND type!='Staff' 
  AND type!='Symbol' AND type!='Waist' 
  AND type!='Wand' AND type!='Wondrous Item' 
  AND type!='Alchemical Item' AND type!='Elixir' 
  AND type!='Reagent' AND type!='Whetstone' 
  AND type!='Other Consumable' AND type!='Companion' 
  AND type!='Mount' AND (type!='Armor' OR (false )) 
  AND (type!='Weapon' OR (false )) 
 ORDER BY type ASC, itemlevel ASC, name ASC

Es scheint gut zu funktionieren, aber es ist auch nicht besonders viel Verkehr (ein paar hundert Zugriffe pro Tag oder so), und ich frage mich, ob es sich lohnt, die Abfragen zu optimieren, um Redundanzen und dergleichen zu entfernen.

0
hinzugefügt bearbeitet
Ansichten: 2
1. Vielen Dank für die Beantwortung der Frage, ich denke, dass die Größe der Abfrage kein Problem für mich sein sollte. 2. Danke allen für die Tipps zum Formatieren des SQL. Ich bin neu und es gibt viele Tricks, die ich nicht kenne (z. B. "type not in (...)"). 3. Als Addendum ist dies eine PHP/MySQL-App
hinzugefügt der Autor Asmor, Quelle
Hier ist ein nützlicher Online-SQL-Formatierer: sqlinform.com
hinzugefügt der Autor micahwittman, Quelle
Wenn Sie versuchen, die Website zu verwenden, scheint es langsam? Wenn es nur ein paar hundert Schläge pro Tag gibt, kann man sich keine Sorgen machen. Erwarten Sie, dass der Traffic steigt? Wie viel? Wenn Sie keine Zeit brauchen, können Sie es einfach tun, um die Seite zukunftssicher zu machen. Aber ist es dann die Zeit, Redundanzen programmatisch zu finden und zu entfernen, die größer sind als die Zeit, die für die Ausführung der Abfrage benötigt wird?
hinzugefügt der Autor Matt Blaine, Quelle

6 Antworten

Wenn Sie Ihre Suchanfrage lesen, möchte ich ein RPG spielen.

Das ist definitiv nicht zu lang. Solange sie gut formatiert sind, würde ich sagen, dass ein praktisches Limit etwa 100 Zeilen beträgt. Danach ist es besser, Unterabfragen in Ansichten zu zerlegen, nur um die Augen nicht zu überqueren.

Ich habe mit einigen Abfragen gearbeitet, die mehr als 1000 Zeilen umfassen, und das ist schwer zu debuggen.

Darf ich übrigens eine umformatierte Version vorschlagen? Dies dient hauptsächlich dazu, die Wichtigkeit der Formatierung zu demonstrieren; Ich vertraue darauf, dass dies leichter zu verstehen sein wird.

select *  
from
  4e_magic_items mi
 ,4e_magic_item_levels mil
 ,4e_monster_sources ms
where mi.id = mil.itemid
  and mi.source = ms.id
  and itemlevel between 1 and 30
  and source not in(16,2,5,13,15,3,4,12,7,14,11,10,8,1,6,9)  
  and type not in(
                  'Arms' ,'Feet' ,'Hands' ,'Head' ,'Neck' ,'Orb' ,
                  'Potion' ,'Ring' ,'Rod' ,'Staff' ,'Symbol' ,'Waist' ,
                  'Wand' ,'Wondrous Item' ,'Alchemical Item' ,'Elixir' ,
                  'Reagent' ,'Whetstone' ,'Other Consumable' ,'Companion' ,
                  'Mount'
                 )
  and ((type != 'Armor') or (false))
  and ((type != 'Weapon') or (false))
order by
  type asc
 ,itemlevel asc
 ,name asc

/*
Some thoughts:
==============
0 - Formatting really matters, in SQL even more than most languages.
1 - consider selecting only the columns you need, not "*"
2 - use of table aliases makes it short & clear ("MI", "MIL" in my example)
3 - joins in the WHERE clause will un-clutter your FROM clause
4 - use NOT IN for long lists
5 - logically, the last two lines can be added to the "type not in" section.
    I'm not sure why you have the "or false", but I'll assume some good reason
    and leave them here.
*/
0
hinzugefügt
Um den Gedanken von David B. zu beantworten ... Meine Erfahrung ist hauptsächlich Oracle/SQL Server, und beide leiden nicht unter der Einschränkung, die Aeon erhoben hat. Wenn MySql sich wirklich so verhält, dann möchten Sie auf jeden Fall Joins im FROM behalten. Ich schlage vor, es in beide Richtungen zu versuchen und die Ausführungszeiten zu vergleichen.
hinzugefügt der Autor JosephStyons, Quelle
Das liegt daran, dass Rüstungen (und Waffen) weiter nach Typ gefiltert werden. Wenn zum Beispiel Cloth und Hide ausgewählt sind, würde das lauten: (type! = 'Armor' ODER (FALSE ODER Einschränkungen wie 'C' ODER Einschränkungen wie 'H')) Die Seite fügt einfach "oder Einschränkungen wie 'was auch immer' hinzu. "In den Parens ist so falsch gebraucht.
hinzugefügt der Autor Asmor, Quelle
Joins in der FROM-Klausel werden Ihre WHERE-Klausel aufräumen. @Aeon - es sollte keinen Leistungsunterschied mit einem richtigen Abfrageoptimierer geben. Ist MySQL so schlecht?
hinzugefügt der Autor Amy B, Quelle
Tatsächlich werden Joins die Dinge beschleunigen, besonders mit den richtigen Indizes. Der Grund dafür ist, dass wenn alle Ihre Klauseln in WHERE sind, MySQL alle Daten holen und dann filtern wird; während bei einem richtigen Join nur die benötigten Daten ausgewählt werden, die einige Größenordnungen kleiner sein können - schneller zu filtern.
hinzugefügt der Autor Aeon, Quelle
Oh, und ... Es sei denn, ich verpasse etwas (Typ! = 'Armor' OR (false)) wird entweder wahr oder falsch sein, aber in jedem Fall wird es die Ergebnismenge nicht beeinflussen Es ist wirklich nicht nötig.
hinzugefügt der Autor Aeon, Quelle
Downvote zum Überfüllen der WHERE-Klausel mit JOIN-Bedingungen.
hinzugefügt der Autor longneck, Quelle

Ich nehme an, du meinst "ausgeschaltet", dass ein Feld keinen Wert hat?

Anstatt zu überprüfen, ob etwas nicht das ist, und es ist auch nicht das, etc. Kannst du nicht einfach überprüfen, ob das Feld null ist? Oder setzen Sie das Feld auf "aus" und prüfen Sie, ob type oder was auch immer "aus" ist.

0
hinzugefügt

Die meisten Datenbanken unterstützen gespeicherte Prozeduren, um dieses Problem zu vermeiden. Wenn Ihr Code schnell genug ist, um ausgeführt zu werden und einfach zu lesen, möchten Sie ihn nicht ändern müssen, um die Kompilierzeit zu verringern.

Eine Alternative besteht darin, vorbereitete Anweisungen zu verwenden, sodass Sie den Treffer nur einmal pro Clientverbindung erhalten und dann nur die Parameter für jeden Aufruf übergeben

0
hinzugefügt

Die Standardbeschränkung für MySQL 5.0 Server ist " 1 MB ", konfigurierbar bis zu 1 GB.

Dies wird über die Einstellung max_allowed_packet für beide Einstellungen konfiguriert Client und Server, und die effektive Begrenzung ist der Vermieter der beiden.

Vorbehalte:

  • Es ist wahrscheinlich, dass diese "Paket" -Begrenzung nicht direkt auf Zeichen in einer SQL-Anweisung abgebildet wird. Sicherlich möchten Sie die Zeichencodierung im Client, einige Paket-Metadaten usw. berücksichtigen.
0
hinzugefügt

Aus praktischer Sicht betrachte ich im Allgemeinen jedes SELECT, das mehr als 10 Zeilen zum Schreiben benötigt (jede Klausel/Bedingung in eine separate Zeile zu setzen), als zu lang, um es einfach zu verwalten. An diesem Punkt sollte es wahrscheinlich als eine gespeicherte Prozedur irgendeiner Art durchgeführt werden, oder ich sollte versuchen, einen besseren Weg zu finden, dasselbe Konzept auszudrücken - möglicherweise durch Erstellen einer Zwischentabelle, um eine Beziehung aufzunehmen, die ich häufig abzufragen scheint.

Ihre Laufleistung kann variieren, und es gibt einige außergewöhnlich lange Fragen, die einen guten Grund haben, zu sein. Aber meine Faustregel ist 10 Zeilen.

Example (mildly improper SQL):

SELECT x, y, z
FROM a, b
WHERE fiz = 1
AND foo = 2
AND a.x = b.y
AND b.z IN (SELECT q, r, s, t
            FROM c, d, e
            WHERE c.q = d.r
              AND d.s = e.t
              AND c.gar IS NOT NULL)
ORDER BY b.gonk

Das ist wahrscheinlich zu groß; die Optimierung würde jedoch weitgehend vom Kontext abhängen.

Denken Sie nur daran, je länger und komplexer die Abfrage ist, desto schwieriger wird es zu warten.

0
hinzugefügt

SELECT @@ global.max_allowed_packet

Dies ist die einzige wirkliche Grenze, die auf einem Server einstellbar ist, so dass es keine wirklich direkte Antwort gibt

0
hinzugefügt