Een Magento 2 shop met 50.000 producten voert bij een categoriebezoek soms 300+ SQL queries uit. Dat is geen feature — dat is een probleem. Hoe je de ergste vertragingen opspoort en oplost.
Magento 2 database optimalisatie — queries die je shop vertragen
Een Magento 2 shop met 50.000 producten voert bij een categoriebezoek soms 300+ SQL queries uit. Dat is geen feature. Dat is een architectuurprobleem dat zich vertaalt naar een trage shop, hoge serverbelasting en een slechte gebruikerservaring.
Database-performance is de meest onderschatte bottleneck in Magento-optimalisatie. Caching maskeert het — totdat de cache leeg is, een deployment plaatsvindt, of een product wordt bijgewerkt. Dan zijn de werkelijke queryproblemen zichtbaar.
Dit artikel laat zien hoe je de ergste vertragingen opspoort en aanpakt.
Wat je leert in dit artikel
- Hoe je de slow query log inschakelt en interpreteert
- Welke Magento-specifieke queries het vaakst voor problemen zorgen
- Index tuning: welke indexes ontbreken en hoe je ze toevoegt
- Flat tables: wanneer ze helpen en wanneer niet
- Concrete optimalisaties met meetbaar resultaat
Stap 1: slow query log inschakelen
Je kunt geen probleem oplossen dat je niet kunt meten. Begin met de MySQL slow query log.
-- Controleer huidige status
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
-- Inschakelen voor de huidige sessie
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL slow_query_time = 1; -- Log queries die langer dan 1 seconde duren
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
-- Queries zonder index ook loggen
SET GLOBAL log_queries_not_using_indexes = 'ON';
Of permanent in /etc/mysql/mysql.conf.d/mysqld.cnf:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
slow query log analyseren met pt-query-digest
Percona Toolkit's pt-query-digest groepeert vergelijkbare queries en toont de slechtste presteerders.
# Installeer Percona Toolkit
sudo apt-get install percona-toolkit -y
# Analyseer slow query log
pt-query-digest /var/log/mysql/slow.log | head -100
Output:
# Rank Query ID Response time Calls R/Call V/M Item
# ==== ================== ============= ====== ======= ===== ====
# 1 0x12E3A9F4 124.2321 40% 1823 0.0681 0.00 SELECT catalog_product_index_price
# 2 0x8B7F2C1A 89.1432 29% 2104 0.0424 0.00 SELECT catalog_category_product_index
# 3 0x4A2E8D7C 54.3211 18% 987 0.0550 0.00 SELECT search_tmp_
Dit toont direct de top-offenders. Kolom 1 is de tijd die deze query-groep totaal heeft gekost.
Veelvoorkomende Magento-queryproblemen
1. EAV-queries op grote catalogi
Magento's EAV-model (Entity-Attribute-Value) splitst productattributen over meerdere tabellen. Een productquery joinet catalog_product_entity met catalog_product_entity_varchar, catalog_product_entity_int, catalog_product_entity_decimal, etc. Per attribuut een aparte join.
-- Typische Magento EAV-query (vereenvoudigd)
SELECT e.entity_id, e.sku,
at_name.value AS name,
at_price.value AS price,
at_status.value AS status
FROM catalog_product_entity e
LEFT JOIN catalog_product_entity_varchar at_name
ON at_name.entity_id = e.entity_id AND at_name.attribute_id = 73
LEFT JOIN catalog_product_entity_decimal at_price
ON at_price.entity_id = e.entity_id AND at_price.attribute_id = 77
LEFT JOIN catalog_product_entity_int at_status
ON at_status.entity_id = e.entity_id AND at_status.attribute_id = 97
WHERE e.entity_id IN (1, 2, 3, 4, 5, ...) -- soms 1000+ IDs
Bij een grote catalogus met veel attributen wordt dit een performance-nachtmerrie.
Oplossing: flat catalog activeren voor producten en categorieën. Dit slaat product- en categoriedata op in gedenormaliseerde flat tables.php bin/magento config:set catalog/frontend/flat_catalog_category 1
php bin/magento config:set catalog/frontend/flat_catalog_product 1
php bin/magento indexer:reindex catalog_category_flat catalog_product_flat
Let op: flat tables werken goed voor read-heavy catalogi, maar reindexing bij updates kost tijd. Bij catalogi die constant wijzigen (prijzen, voorraad) is de reindex-overhead een afweging.
2. Ontbrekende indexes op filtercombinaties
Een layered navigation-filter op kleur + maat + merk genereert een complexe query. Als de betrokken kolommen geen samengestelde index hebben, scant MySQL de volledige tabel.
-- Identificeer queries zonder index
EXPLAIN SELECT cp.entity_id
FROM catalog_product_index_eav cpie
WHERE cpie.attribute_id = 93 -- kleur
AND cpie.value = 'Rood'
AND cpie.store_id = 1;
-- Als type = 'ALL' in de EXPLAIN-output: geen index gebruikt
-- Als type = 'ref' of 'range': index gebruikt
Indexes toevoegen:
-- Index voor layered navigation queries
ALTER TABLE catalog_product_index_eav
ADD INDEX idx_attr_val_store (attribute_id, value, store_id);
-- Index voor prijsfiltering
ALTER TABLE catalog_product_index_price
ADD INDEX idx_website_group_store (website_id, customer_group_id, store_id);
3. N+1 queries in product collections
Een categorieoverzicht laadt een productcollectie. Voor elk product worden dan afzonderlijk prijzen, afbeeldingen en reviewscores opgevraagd. Bij 24 producten op een pagina: 24 × 3 = 72 extra queries.
// Problematisch: aparte query per product
foreach ($products as $product) {
$price = $this->priceHelper->getPrice($product); // 1 query per product
$reviews = $this->reviewFactory->getEntitySummary($product); // nog 1 query
}
// Beter: batch-loading via de collection
$collection = $this->productCollectionFactory->create();
$collection->addAttributeToSelect(['name', 'price', 'small_image', 'url_key']);
$collection->addMinimalPrice();
$collection->addFinalPrice();
$collection->addTaxPercents();
$collection->load();
4. Grote quote-tabellen
De quote en quote_item tabellen groeien zonder limiet. Verlaten winkelwagens worden standaard 30 dagen bewaard. Na een jaar: een quote-tabel met miljoenen records die bij elke checkout-query wordt bevraagd.
-- Controleer de omvang
SELECT COUNT(*) as totaal_quotes,
COUNT(CASE WHEN is_active = 0 THEN 1 END) as verlaten_quotes,
COUNT(CASE WHEN updated_at < DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1 END) as oud_30_dagen
FROM quote;
Opschonen via de ingebouwde Magento cronjob:
php bin/magento config:set catalog/magento_catalogpermissions/grant_catalog_category_view 0
# Of via de Magento CLI
php bin/magento cron:run --group=index
Of handmatig in SQL (maak eerst een backup):
-- Verwijder verlaten quotes ouder dan 90 dagen
DELETE FROM quote
WHERE is_active = 0
AND updated_at < DATE_SUB(NOW(), INTERVAL 90 DAY);
-- Bijbehorende quote items worden via foreign key constraint verwijderd
-- (als cascade delete is geconfigureerd)
5. Log-tabellen die uit de hand lopen
report_event, customer_log, magento_logging_event kunnen enorm groeien. Ze worden bevraagd bij admin-rapportages en soms ook bij frontendoperaties.
-- Controleer tabelgroottes
SELECT table_name,
ROUND(data_length / 1024 / 1024, 2) AS data_mb,
ROUND(index_length / 1024 / 1024, 2) AS index_mb,
table_rows
FROM information_schema.tables
WHERE table_schema = 'jouw_database_naam'
ORDER BY data_length DESC
LIMIT 20;
EXPLAIN gebruiken voor query-analyse
EXPLAIN is het krachtigste hulpmiddel voor database-optimalisatie.
EXPLAIN SELECT e.entity_id, e.sku
FROM catalog_product_entity e
JOIN catalog_product_index_price pip
ON pip.entity_id = e.entity_id
AND pip.website_id = 1
AND pip.customer_group_id = 0
WHERE pip.final_price BETWEEN 50 AND 100
ORDER BY pip.final_price ASC
LIMIT 24;
Interpretatie van de output:
| Kolom | Wat het betekent |
|---|---|
type = ALL | Volledige tabelscan — probleem |
type = index | Index-scan — beter maar nog niet optimaal |
type = ref | Index-lookup op gelijkheid — goed |
type = range | Index-range scan — goed voor BETWEEN/IN |
rows | Geschat aantal te scannen rijen |
Extra = Using filesort | Sortering kan niet via index — overweeg index |
Extra = Using temporary | Tijdelijke tabel nodig — kan op index worden verbeterd |
MySQL configuratie voor Magento
Een aantal MySQL-instellingen hebben grote impact op Magento-performance.
# /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
# InnoDB buffer pool: stel in op 70-80% van het beschikbare RAM
# Op een server met 8GB RAM:
innodb_buffer_pool_size = 6G
# Buffer pool instances: 1 per GB buffer pool, max 8
innodb_buffer_pool_instances = 6
# Query cache uitschakelen (schaalt slecht bij veel writes)
query_cache_type = 0
query_cache_size = 0
# Verhoog open files limit voor grote Magento-installaties
open_files_limit = 65536
table_open_cache = 4096
# Logboek voor slow queries
slow_query_log = 1
long_query_time = 1
Concrete resultaten
Op een klantinstallatie met 80.000 producten hebben wij de volgende optimalisaties uitgevoerd:
| Optimalisatie | Voor | Na | Verbetering |
|---|---|---|---|
| Flat catalog activeren | 2.1s categoriepagina | 0.8s | -62% |
| Indexes EAV-tabellen | 1.4s layered nav filter | 0.3s | -79% |
| Quote-tabel opschonen (4M → 180K rijen) | 0.9s checkout step 1 | 0.2s | -78% |
| InnoDB buffer pool 1G → 6G | 450ms gem. query | 95ms gem. query | -79% |
Dit zijn productieresultaten, gemeten voor en na zonder andere wijzigingen.
Veelgemaakte fouten
- Indexer op "Update on Save" zetten voor grote catalogi — Dit triggert reindexing bij elke productopslag. Gebruik "Update by Schedule" en laat de cronjob de reindexing beheren.
- Geen database-backups maken voor optimalisaties — Een
ALTER TABLEop een tabel van 10GB duurt lang en kan misgaan. Altijd backup, altijd test op staging.
- N+1 problemen oplossen met caching — Caching maskeert N+1 queries maar lost ze niet op. Bij cache misses is het alsnog traag.
Best practices
| Practice | Waarom |
|---|---|
Voer wekelijks pt-query-digest uit | Vroeg signaleren voorkomt grotere problemen |
| Test alle queries met EXPLAIN | Visualiseert indexgebruik direct |
| Houd log-tabellen klein via cronjobs | Grote log-tabellen vertragen admin-queries |
| Gebruik staging voor zware ALTER TABLE operaties | Productie-impact testen voor uitvoering |
Monitor innodb_buffer_pool_read_requests vs innodb_buffer_pool_reads | Buffer pool hit ratio moet boven 99% zijn |
Conclusie
Database-optimalisatie in Magento 2 is geen eenmalige actie. Het is een cyclus: meten, analyseren, optimaliseren, meten.
De slow query log en EXPLAIN zijn de twee tools die je hiervoor nodig hebt. De flat catalog en correcte indexes zijn de twee maatregelen die het meeste opleveren. De buffer pool-instelling is de makkelijkste win.
Begin met meten. De problemen wijzen zichzelf aan.
Wil je een volledige database-audit op jouw Magento-installatie? Bekijk onze Magento 2 monitoring-aanpak of neem direct contact op via onze Magento-pagina. Lees ook ons artikel over Elasticsearch vs OpenSearch voor Magento 2 voor de zoekinfrastructuur.
Heeft jouw Magento-shop last van trage database-queries? Neem contact op voor een performance-audit.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →