Ik onderhoud een webshop die gebouwd is met Prestashop. Sinds een upgrade naar een recente versie hebben we regelmatig last van downtime. Middels een beheertool van Plesk heb ik de boosdoener gevonden. Er is een specifieke query die heel lang loopt (3 min+). Deze query wordt veroorzaakt door bezoekers van de webshop. Heb je meerdere bezoekers die deze query veroorzaken dan ben je het haasje. De query heb ik kunnen relateren aan de filters in de categorieën. Je kunt bv filteren op kleur, maat en andere eigenschappen. Ik ben erachter dat het nog goed gaat bij het selecteren van 3 verschillende filters. Zodra je de 4e filter erbij klikt ontstaat een query die minstens enkele minuten loopt. De site draait op MariaDB 10.5.10.
Dit is de betreffende query die wordt afgetrapt (deze duurt +- 3min). Hierin zijn nu 4 filters verwerkt in de query:
Naar mijn idee wordt er geredeneerd over een kleine dataset. Via een explain van bovenstaande query zijn er maar enkele 100'en records mee gemoeid. Of zie ik dat verkeerd?
Met 3 filters duurt de query meestal minder dan een seconde, soms een paar seconden.
Om een idee van de omvang te geven. Aantal records per gerelevante tabel (afgerond):
Als ik de eerste inner query (select op regel 2) los uitvoer dan krijg ik en maar een klein setje results, en de query is nagenoeg instant uitgevoerd.
Server specs:
VPS bij Transip, 4 cpu's, 8GB RAM.
MySQL settings:
Deze query is opgebouwd door Prestashop en kan ik niet zomaar aanpassen. Het is namelijk geen platte query, maar wordt opgebouwd via een Prestashop library om de filters om te zetten naar een query. Ik wil eerst snappen wat er aan de hand is, daarna kan ik werken aan een fix in de prestashop code of MySQL configuratie.
Wie kan mij helpen waar ik de oorzaak moet zoeken?
Dit is de betreffende query die wordt afgetrapt (deze duurt +- 3min). Hierin zijn nu 4 filters verwerkt in de query:
SQL:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| SELECT Count(DISTINCT p.id_product) c FROM (SELECT p.id_product, p.id_manufacturer, Sum(sa.quantity) AS quantity, p.condition, p.weight, p.price, psales.quantity AS sales, cp.position FROM ps_product p LEFT JOIN ps_product_attribute pa ON ( p.id_product = pa.id_product ) LEFT JOIN ps_product_attribute_combination pac ON ( pa.id_product_attribute = pac.id_product_attribute ) LEFT JOIN ps_stock_available sa ON ( p.id_product = sa.id_product AND Ifnull(pac.id_product_attribute, 0) = sa.id_product_attribute AND sa.id_shop = 1 AND sa.id_shop_group = 0 ) LEFT JOIN ps_product_sale psales ON ( psales.id_product = p.id_product ) INNER JOIN ps_category_product cp ON ( p.id_product = cp.id_product ) INNER JOIN ps_category c ON ( cp.id_category = c.id_category AND c.active = 1 ) INNER JOIN ps_product_shop ps ON ( p.id_product = ps.id_product AND ps.id_shop = 1 AND ps.active = true ) LEFT JOIN ps_feature_product fp ON ( p.id_product = fp.id_product ) LEFT JOIN ps_feature_product fp_1 ON ( p.id_product = fp_1.id_product ) LEFT JOIN ps_feature_product fp_2 ON ( p.id_product = fp_2.id_product ) LEFT JOIN ps_feature_product fp_3 ON ( p.id_product = fp_3.id_product ) WHERE (( fp.id_feature_value = 39 )) AND (( fp_1.id_feature_value = 149 )) AND (( fp_2.id_feature_value = 273 )) AND (( fp_3.id_feature_value IN ( 3555, 312 ) )) AND p.visibility IN ( 'both', 'catalog' ) AND c.nleft >= 3 AND c.nright <= 138 AND ps.id_shop = '1' GROUP BY p.id_product) p LEFT JOIN ps_feature_product fp ON ( p.id_product = fp.id_product ) LEFT JOIN ps_feature_product fp_1 ON ( p.id_product = fp_1.id_product ) LEFT JOIN ps_feature_product fp_2 ON ( p.id_product = fp_2.id_product ) LEFT JOIN ps_feature_product fp_3 ON ( p.id_product = fp_3.id_product ) WHERE (( fp.id_feature_value = 39 )) AND (( fp_1.id_feature_value = 149 )) AND (( fp_2.id_feature_value = 273 )) AND (( fp_3.id_feature_value IN ( 3555, 312 ) )) |
Naar mijn idee wordt er geredeneerd over een kleine dataset. Via een explain van bovenstaande query zijn er maar enkele 100'en records mee gemoeid. Of zie ik dat verkeerd?
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | PRIMARY | fp_2 | ref | id_feature_value, id_product | id_feature_value | 4 | const | 233 | Using index |
1 | PRIMARY | fp_3 | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.fp_2.id_product | 3 | Using where; Using index |
1 | PRIMARY | fp_1 | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.fp_2.id_product | 3 | Using where; Using index |
1 | PRIMARY | fp | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.fp_2.id_product | 3 | Using where; Using index |
1 | PRIMARY | <derived2> | ref | key0 | key0 | 4 | presta_tst2.fp_2.id_product | 2 | "" |
2 | LATERAL DERIVED | p | eq_ref | PRIMARY | PRIMARY | 4 | presta_tst2.fp_1.id_product | 1 | Using where |
2 | LATERAL DERIVED | fp_3 | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.p.id_product | 3 | Using where; Using index |
2 | LATERAL DERIVED | fp_2 | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.p.id_product | 3 | Using index |
2 | LATERAL DERIVED | fp_1 | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.p.id_product | 3 | Using index |
2 | LATERAL DERIVED | fp | ref | id_feature_value, id_product | id_product | 4 | presta_tst2.p.id_product | 3 | Using index |
2 | LATERAL DERIVED | c | range | PRIMARY, nleftrightactive, nright, activenleft, activenright | activenright | 5 | "" | 55 | Using index condition; Using where; Using join buffer (flat, BNL join) |
2 | LATERAL DERIVED | ps | eq_ref | PRIMARY | PRIMARY | 8 | presta_tst2.p.id_product,const | 1 | Using where |
2 | LATERAL DERIVED | pa | ref | product_default, product_attribute_product | product_default | 4 | presta_tst2.p.id_product | 1 | Using index |
2 | LATERAL DERIVED | pac | ref | id_product_attribute | id_product_attribute | 4 | presta_tst2.pa.id_product_attribute | 1 | Using where; Using index |
2 | LATERAL DERIVED | cp | eq_ref | PRIMARY, id_product, id_category | PRIMARY | 8 | presta_tst2.c.id_category, presta_tst2.p.id_product | 1 | "" |
2 | LATERAL DERIVED | sa | eq_ref | product_sqlstock, id_shop, id_shop_group, id_product, id_product_attribute | product_sqlstock | 16 | presta_tst2.p.id_product, func,const, const | 1 | Using where |
2 | LATERAL DERIVED | psales | eq_ref | PRIMARY | PRIMARY | 4 | presta_tst2.p.id_product | 1 | "" |
Met 3 filters duurt de query meestal minder dan een seconde, soms een paar seconden.
Om een idee van de omvang te geven. Aantal records per gerelevante tabel (afgerond):
Table | Aantal records |
---|---|
ps_product | 4200 |
ps_feature_product | 27000 |
ps_product_attribute | 7500 |
ps_product_attribute_combination | 7200 |
ps_stock_available | 12000 |
ps_product_sale | 2100 |
ps_category_product | 11000 |
ps_category | 350 |
ps_product_shop | 4200 |
Als ik de eerste inner query (select op regel 2) los uitvoer dan krijg ik en maar een klein setje results, en de query is nagenoeg instant uitgevoerd.
Server specs:
VPS bij Transip, 4 cpu's, 8GB RAM.
MySQL settings:
code:
1
2
3
4
5
6
7
8
9
10
11
12
| [mysqld] table_open_cache = 1000 read_buffer_size = 2M read_rnd_buffer_size = 1M thread_cache_size = 80 join_buffer_size = 2M sort_buffer_size = 2M max_connections = 400 tmp_table_size = 32M max_heap_table_size = 32M table_definition_cache = 1000 performance_schema = OFF |
Deze query is opgebouwd door Prestashop en kan ik niet zomaar aanpassen. Het is namelijk geen platte query, maar wordt opgebouwd via een Prestashop library om de filters om te zetten naar een query. Ik wil eerst snappen wat er aan de hand is, daarna kan ik werken aan een fix in de prestashop code of MySQL configuratie.
Wie kan mij helpen waar ik de oorzaak moet zoeken?
Ruisende versterker: schakel je subwoofer in.