TL;DRLe modèle EAV (Entité-Attribut-Valeur) est la fondation de la base de données de Magento : il explique pourquoi un produit n'a pas " une ligne, une colonne par propriété " comme dans une base classique, mais est reconstitué à la demande à partir de plusieurs tables. Comprendre ce modèle est indispensable pour qui doit un jour écrire une requête SQL directe, déboguer une lenteur ou créer un attribut personnalisé sur Magento.

Le problème que l'EAV résout#

Une table de base de données classique fixe ses colonnes à la création : un produit aurait une colonne nom, une colonne prix, une colonne couleur. Ça fonctionne tant que tous les produits partagent les mêmes propriétés. Magento est pensé pour des catalogues où un t-shirt a une taille et une couleur, une carte cadeau a un montant et une date d'expiration, et un marchand peut ajouter demain un attribut " matière " sans qu'un développeur touche au schéma de la base.

Ajouter une colonne à chaque nouvel attribut obligerait à modifier la structure de la table à chaque fois (une opération lourde sur une table de plusieurs millions de lignes) et laisserait des colonnes vides pour tous les produits qui n'utilisent pas cet attribut. L'EAV répond à ce problème en sortant les propriétés de la table de l'entité : ajouter un attribut, c'est ajouter une ligne dans une table de catalogue, jamais une colonne.

L'Entité : la table qui identifie la chose#

La table d'entité est la plus proche de ce qu'on imaginerait dans un modèle classique, mais réduite à l'essentiel. Pour les produits, c'est catalog_product_entity : elle ne contient que entity_id (l'identifiant unique), sku, attribute_set_id, type_id (simple, configurable, virtuel…) et les dates de création/modification. Aucune propriété métier – ni nom, ni prix, ni description – ne s'y trouve : cette table dit seulement " ce produit existe, voici son identifiant ". Chaque type d'entité (produit, catégorie, client, commande) a sa propre table de ce genre, recensée dans eav_entity_type, qui fait le lien entre un type d'entité et les tables associées.

L'Attribut : le catalogue des propriétés possibles#

Tous les attributs de tous les produits sont décrits une seule fois dans la table eav_attribute : attribute_id, attribute_code (le nom technique, comme color ou weight), entity_type_id (à quel type d'entité il s'applique), backend_type (dans quelle table de valeur il sera rangé : varchar, int, decimal, text, datetime), et une série de réglages (obligatoire, filtrable, comparable, visible en recherche…). Un attribut " couleur " n'existe donc qu'une fois dans la base, même s'il s'applique à cent mille produits.

Les attributs sont ensuite organisés en jeux d'attributs (eav_attribute_set, par exemple " Vêtements " ou " Par défaut ") et en groupes à l'intérieur de ces jeux (eav_attribute_group, par exemple " Général ", " Prix ", " Images " dans l'interface d'administration). La table pivot eav_entity_attribute relie un attribut à un jeu et à un groupe : c'est elle qui décide quels champs apparaissent, et dans quel onglet, quand on édite un produit dans le back-office.

La Valeur : où vit vraiment la donnée#

C'est la partie la moins intuitive du modèle : la valeur d'un attribut pour un produit donné n'est ni dans catalog_product_entity ni dans eav_attribute, mais dans une table dédiée au type de donnée de cet attribut. Magento maintient une table de valeur par backend_type :

  • catalog_product_entity_varchar – textes courts (nom, référence visuelle…)
  • catalog_product_entity_int – entiers (statut, identifiants de sélection…)
  • catalog_product_entity_decimal – nombres décimaux (prix, poids…)
  • catalog_product_entity_text – textes longs (description)
  • catalog_product_entity_datetime – dates (disponibilité à partir du…)

Chacune de ces tables partage la même structure : value_id, attribute_id, store_id, entity_id, value. Une ligne dans catalog_product_entity_decimal ne veut donc rien dire seule : elle prend son sens uniquement rapprochée de son attribute_id (pour savoir si c'est un prix ou un poids) et de son entity_id (pour savoir de quel produit il s'agit).

Comment une ligne complète se recompose#

Obtenir le nom et le prix d'un produit demande de reconstituer l'information à travers plusieurs tables, en plusieurs étapes :

  1. Trouver l'attribute_id de name et de price dans eav_attribute, pour le type d'entité " produit ".
  2. Savoir que name a pour backend_type " varchar " et price " decimal ", donc consulter catalog_product_entity_varchar pour l'un et catalog_product_entity_decimal pour l'autre.
  3. Dans chaque table, filtrer sur entity_id = l'identifiant du produit et attribute_id = celui trouvé à l'étape 1.

En SQL simplifié, retrouver le nom d'un produit ressemble à :

SELECT v.value
FROM catalog_product_entity_varchar v
JOIN eav_attribute a ON a.attribute_id = v.attribute_id
WHERE v.entity_id = 123
  AND a.attribute_code = 'name'
  AND v.store_id IN (0, 1)
ORDER BY v.store_id DESC
LIMIT 1;

Chaque propriété supplémentaire demandée (description, poids, couleur…) ajoute une jointure du même genre. C'est le mécanisme central à retenir : là où une table classique donne toutes les colonnes d'un coup, l'EAV assemble le produit attribut par attribut, avec autant de requêtes ou de jointures que d'attributs consultés.

Le rôle du store_id : une valeur par vue de boutique#

La colonne store_id des tables de valeur permet à un même attribut d'avoir une valeur différente selon la vue de boutique (utile pour un site multilingue ou multi-marché). La valeur par défaut est enregistrée avec store_id = 0 ; une vue de boutique spécifique peut ensuite écraser cette valeur pour elle seule, avec son propre store_id. C'est pourquoi la requête ci-dessus trie par store_id décroissant avant de prendre la première ligne : elle privilégie la valeur spécifique à la boutique si elle existe, et retombe sur la valeur par défaut sinon.

Le prix de la flexibilité, et comment Magento le compense#

Reconstituer un produit avec une dizaine d'attributs par des jointures EAV, répété pour une liste de plusieurs centaines de produits sur une page catégorie, serait beaucoup trop lent pour un site en production. Magento contourne ce coût avec des tables d'index précalculées, reconstruites en arrière-plan par les indexeurs (catalog_product_index_price, catalog_category_product_index…) : ces tables stockent déjà la donnée " à plat ", prête à être lue sans jointure, et sont régénérées chaque fois qu'un produit ou un prix change. Le modèle EAV reste la source de vérité pour l'administration et l'édition ; l'affichage côté boutique lit, lui, des tables optimisées pour la lecture.

Questions fréquentes#

Pourquoi Magento n'utilise-t-il pas simplement une table à plat comme WooCommerce ?#

Parce que Magento cible des catalogues hétérogènes et personnalisables sans intervention d'un développeur à chaque nouvel attribut : l'EAV permet à un marchand d'ajouter un attribut depuis l'administration, sans migration de base de données. C'est un choix de flexibilité, payé en complexité de lecture.

Tous les attributs d'un type d'entité utilisent-ils la même table de valeur ?#

Non : chaque attribut est rangé dans la table correspondant à son backend_type (varchar, int, decimal, text ou datetime), défini une fois pour toutes à la création de l'attribut. Deux attributs voisins dans l'administration peuvent donc vivre dans deux tables différentes.

Peut-on créer un attribut sans passer par le modèle EAV ?#

Non, sur les entités EAV natives de Magento (produit, catégorie, client), tout nouvel attribut passe par eav_attribute et une table de valeur existante. Certaines extensions personnalisées choisissent en revanche des tables " plates " classiques pour leurs propres besoins, hors du cœur EAV.

Le modèle EAV ralentit-il vraiment un site Magento ?#

Sans les tables d'index, oui, nettement, sur les pages qui listent beaucoup de produits. Avec les indexeurs correctement configurés et à jour (mode " Mise à jour à la sauvegarde " ou planifiée), l'impact reste limité côté boutique, l'essentiel du coût des jointures EAV étant reporté sur la reconstruction des index en arrière-plan.

Article rédigé le 21/09/2026 par l'équipe Websource.