Queries Verbesserung

OnDemand

Top Contributor
Hi zusammen,

hab hier ein paar Queries die übel lahm sind, trotz Indexe usw.

Hat jemand ne Idee wie man die vereinfachen kann? Mit Join & Co hab ich leider noch keine Erfahrung (wird dann wohl mal Zeit)

SQL:
SELECT * FROM products p WHERE p.webshop_active=true AND p.parent = false AND p.sales_price_calculated IS NOT NULL AND NOT EXISTS (SELECT null FROM products_marketplace_mapping pms WHERE pms.product_id = p.id AND pms.marketplace_id= :marketplaceId) LIMIT 100
Ohne die Limiterung dauert das übelst ewig (dann fehlen natürlich auch Daten)
 

mihe7

Top Contributor
Dürfte dem entsprechen (ungetestet):
SQL:
SELECT * FROM products p 
  LEFT JOIN products_marketplace_mapping pms ON p.id = pms.product_id
  WHERE (pms.product_id is null or pms.marketplace_id= :marketplaceId)
    AND p.webshop_active = true AND p.parent = false
 

OnDemand

Top Contributor
Ach Gott, das kapiert ich nicht auf anhieb. Da muss ich mich erstmal belesen was LEFT und RIGHT Join ist.
Kann die Geschwindigkeit aber Grundsätzlich mit dem Query zu tun haben?

Hier ist noch so ein Murks. Könntest du mir hier auch helfen? wäre grandio, dann hab ich auch direkt 2 Beispiele die ich mit am WE auseinanderpflücken kann.
Java:
SELECT * FROM products p, products_variants WHERE p.id = pv.id p.webshop_active=true AND p.parent = true AND pv.sales_price_calculated IS NOT NULL AND NOT EXISTS (SELECT null FROM products_marketplace_mapping pms WHERE pms.product_id = p.id) LIMIT 100
 

mihe7

Top Contributor
Da muss ich mich erstmal belesen was LEFT und RIGHT Join ist.
Das ist recht einfach: ein JOIN verknüpft zwei Tabellen ensprechend der ON-Klausel. Eine Tabelle steht links und eine rechts vom JOIN-Operator.

Bei einem INNER JOIN enthält das Ergebnis nur die Zeilen aus beiden Tabellen, die der ON-Klausel entsprechen.
Bei einem LEFT JOIN enthält das Ergebnis in jedem Fall alle Zeilen aus der linken Tabelle. Es kann also Sätze in der rechten Tabelle geben, die der ON-Klausel nicht entsprechen. In dem Fall werden die Spalten der rechten Tabelle im Ergebnis einfach mit NULL belegt.
Bei einem RIGHT JOIN ist es umgekehrt.

Einfach mal einfachen Beispielen ausprobieren, dann siehst Du das sofort.

SELECT * FROM products p, products_variants WHERE p.id = pv.id p.webshop_active=true AND p.parent = true AND pv.sales_price_calculated IS NOT NULL AND NOT EXISTS (SELECT null FROM products_marketplace_mapping pms WHERE pms.product_id = p.id) LIMIT 100
Hier fehlt was nach p.id = pv.id. Dieser Vergleich in der WHERE-Klausel entspricht übrigens einem INNER JOIN (SELECT * FROM products p INNER JOIN products_variants pv ON p.id = pv.id).
 

OnDemand

Top Contributor
Hab es mal eingebaut, soooooo viel schneller scheint es nicht zu sein. Ich komm nicht mal auf meinen Login so schnell. Das läft übel lange, kann es sein dass der Query so viel Resourcen braucht? Was könnte man in dem Fall machen?

Nur die ID geben lassen und dann jedes Objekt nach Bedarf einzeln holen statt alle in einer List?
 

OnDemand

Top Contributor
Ja die sind gesetzt soweit. Problem ist glaube der RAM. Der Query liest da 190.000 Objekte aus, die recht viele abhängige Objekte laden. Dadurch explodiert der RAM. Müsste es vermutlich dann doch splitten oder?
 

OnDemand

Top Contributor
Öhm das klappt bei mir nicht. Weder mit ANALYZE noch mit EXPLAIN ANALAYZE
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SELECT * FROM products' at line 1
 

mrBrown

Super-Moderator
Mitarbeiter
Versuch mal nur EXPLAIN, ohne ANALYZE.


Vielleicht solltest du die Version mal updaten, die ist ja dann über 2 Jahre alt...
 

OnDemand

Top Contributor
ah mit EXPLAIN klappt es. Aber was genau sagt mir das
SQL:
mysql> EXPLAIN SELECT * FROM products p LEFT JOIN products_marketplace_mapping pms ON p.id = pms.product_id WHERE (pms.product_id is null or pms.marketplace_id= 2) AND p.wective = true AND p.parent = false;
+----+-------------+-------+------------+------+-------------------------------------------+-------------------------------------------+---------+--------------------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys                             | key                                       | key_len | ref                | rows  | filtered | Extra       |
+----+-------------+-------+------------+------+-------------------------------------------+-------------------------------------------+---------+--------------------+-------+----------+-------------+
|  1 | SIMPLE      | p     | NULL       | ref  | products_idx_webshop_ac_parent_sales_calc | products_idx_webshop_ac_parent_sales_calc | 4       | const,const        | 90782 |   100.00 | NULL        |
|  1 | SIMPLE      | pms   | NULL       | ref  | product_id,product_idVariantMarketplace   | product_id                                | 5       | database.p.id |     1 |   100.00 | Using where |
+----+-------------+-------+------------+------+-------------------------------------------+-------------------------------------------+---------+--------------------+-------+----------+-------------+
2 rows in set, 1 warning (0.00 sec)
 

LimDul

Top Contributor
Wieviel Rows soll das Query denn zurückgeben? Und wo wird das Query verwendet? Ist es langsam, wenn du es in MySQL ausführst? Oder kommen da etwa 190.000 Zeilen zurück, die dann in Java-Objekte geladen werden?

Dann ist nicht das Query das Problem, sondern die Fachlogik - man sollte eigentlich nie so viele komplette Objekt-Geflechte direkt im Speicher laden, das hört sich mehr nach Batch-Verarbeitung oder Co an.
 

OnDemand

Top Contributor
Joa das könnte sein, dass das Mapping so lange braucht / viel Recource. Der Query (Spring Boot Repository) baut daraus eine List.

Hab da an dem Produkt einige Sub-Objekte dran. Ist mir schon ein paar Mal auf die Füße gefallen. Wenn die aber von einander ablöse oder aber mit Lazy arbeite hab ich immer das Problem, dass die Sub-Objekte nicht mitgelöscht werden obwohl alles casdiert wird.

Müsste dann also die Objekte wirklich lose von einander machen und wenn jemand ein "Produkt" löscht, dann die Unterobjekte auch löschen "per Hand" statt das vom Hibernate machen zu lassen.

Beispiel:
Produkt
- List<Images>
- List <Attributes>

dabei kann jede List 10 Images haben und 100 Attribute. Das ist dann in der Tat einiges, was da geladen werden muss.

Oder Variante 2 wäre, dass ich mit von dem Query nur eine List mit IDs geben lasse, und die verarbeitende Methode dann jeweils das Produkt per ID holt. Macht zwar viele einzelne Roundtrips, aber dafür nicht so viel Last aufeinmal
 

mrBrown

Super-Moderator
Mitarbeiter
Joa das könnte sein, dass das Mapping so lange braucht / viel Recource.
Bevor du irgendwo anfängst zu optimieren, solltest du in jedem Fall erstmal rausfinden, an welchen Stellen genau das langsam ist...


ah mit EXPLAIN klappt es. Aber was genau sagt mir das
Oftmals kann man da offensichtliche Probleme erkennen.

Um da aber in deinem Fall was sinnvolles sagen zu können, bräuchte man vermutlich einmal ein Beispiel, damit man zumindest die Tabelle mit passenden Typen und Indizes etc nachbauen kann.
 

LimDul

Top Contributor
Bevor du irgendwo anfängst zu optimieren, solltest du in jedem Fall erstmal rausfinden, an welchen Stellen genau das langsam ist...
Das kann ich nur unterschreiben. Alles andere ist stochern im Nebel. Das wichtigste bei Performance-Problemen ist den Finger genau auf die Stelle zu legen, die das Problem verursacht. Und nach den Indizien hier würde ich nicht das Query als das Problem ansehen sondern die Verarbeitung der Daten. Aber das weiß man genau, wenn man mal gemessen hat.
 

mrBrown

Super-Moderator
Mitarbeiter
Und nach den Indizien hier würde ich nicht das Query als das Problem
Wobei man die Indizes wahrscheinlich schon verbessern könnte, products_idx_webshop_ac_parent_sales_calc klingt zumindest so, als hätte es was mit der parent-Column zu tun (ist die einzige, die vom Namen ansatzweise passt), die allerdings ein boolean und damit erstmal komisch ist. Das pms.marketplace_id nicht benutzt wird könnte sich auch negativ auswirken.

Aber dafür müsste man die Tabelle sehen, und Sinn macht es natürlich erst, wenn die Query selbst überhaupt zu langsam ist...
 

Ähnliche Java Themen

Neue Themen


Oben