janvier 30 2009
Améliorer les performances de VirtueMart : Proposition d’une nouvelle table
Tagged Under : Joomla, performances, VirtueMart
Voici une proposition permettant d’améliorer le parcours de l’arborescence catégorie de VirtueMart, au détriment de la vitesse d’écriture. Ce billet fait directement suite à mon article « Améliorer les performances de VirtueMart« .
Cette méthode nécessite de créer une nouvelle table que nous appellerons #__{vm}_category_tree, dont voici le schéma :
- category_id : identifiant de la catégorie
- category_path : fil d’ariane de la catégorie sous forme d’un liste dénormalisée d’identifiant de catégorie séparée par « , »
- level : niveau de profondeur de la catégorie étudiée
Par exemple, une catégorie ayant un « fil d’ariane » ayant pour valeur « ,1,6,184, » serait de niveau 4 (étant donné qu’il existe trois niveaux de catégories parentes). Sa catégorie parente serait la catégorie « 184″ qui aurait elle même comme parent « 6″ qui aurait elle même comme parent « 1″ qui n’aurait pas de catégorie parente.
Le choix du séparateur « , » permettra d’utiliser au besoin la colonne presque directement dans une requête SQL via le mot clé « in » si besoin.
Voici le SQL permettant de créer cette table :
`category_id` int(11) NOT NULL,
`category_path` varchar(255) NOT NULL,
`level` int(11) NOT NULL,
KEY `category_id` (`category_id`),
KEY `category_path` (`category_path`),
KEY `level` (`level`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Pour alimenter cette table, il faut d’abord executer une fois la requete suivante :
`#__{vm}_category_tree`
(category_id,category_path,level)
SELECT
`#__{vm}_category.category_id`,
",",
1
FROM
`#__{vm}_category`
INNER JOIN
`#__{vm}_category_xref`
ON
`#__{vm}_category_xref`.category_child_id=`#__{vm}_category`.category_id
WHERE
`#__{vm}_category`.category_publish="Y"
AND
`#__{vm}_category_xref`.category_parent_id=0;
Il faut ensuite exécuter pour chaque niveau :
`#__{vm}_category_tree`
(category_id,category_path,level)
SELECT
`#__{vm}_category`.category_id,
concat(IFNULL(parent_leaf.category_path,""),`#__{vm}_category_xref`.category_parent_id,";"),
IFNULL(parent_leaf.level+1,0)
FROM
`#__{vm}_category`
INNER JOIN
`#__{vm}_category_xref`
ON
`#__{vm}_category_xref`.category_child_id=`#__{vm}_category`.category_id
LEFT OUTER JOIN
`#__{vm}_category_tree` parent_leaf
ON
parent_leaf.category_id=`#__{vm}_category_xref`.category_parent_id
WHERE
`#__{vm}_category`.category_publish="Y"
AND
`#__{vm}_category_xref`.category_parent_id IN (SELECT
category_id FROM `#__{vm}_category_tree` WHERE level=?)
Le remplissage « au fil de l’eau » de cette table, fera l’objet d’autres billets.
Maintenant pour connaître tous les enfants directs et indirects d’une catégorie (« 5″ par exemple), il suffit d’éxécuter la requête suivante:
FROM `#__{vm}_category_tree`
WHERE category_path LIKE ',5,%';
Une sacré économie de requetes SQL. Le résultat peut-être placée en cache si cela est possible. Il est également possible de complexifier cette requête en y rajoutant par exemple une jointure avec la table #__{vm}_category.
Si vous êtes intéressé par cette modification, merci d’appuyer ma demande sur le forum.


Salut, et merci pour tes expliquations. J’ai effectivement le même problème avec une grande quantité de produits et surtout un arbre de catégories conséquents en trois niveau.
J’ai retrouvé ton post sur le forum mais tout ça date d’environ deux ans. Qu’en est-il devenu de ce sujet exactement ?
Salut,
j’utilise cette technique sur la plupart des sites que je maintiens. La table « #__{vm}_category_tree » est remplie la nuit par un batch.
Un autre point important au niveau des perfomances, je pense, c’est la réécriture d’URL. L’idéal, serait que la réécriture d’une URL ne nécessite qu’une seule requête SQL (sans cache). Si la réécriture d’URL est trop complexe pour se faire en une requête (ou si la requête nécessaire est complexe), l’idéal est de « préparer » les URLs dans les batchs de nuit.