Comparaison des modes de requête Select avec Drupal 7

Comparaison des modes de requête simple (select) Drupal

Pour réaliser des requêtes de type SELECT, Drupal 7 propose au moins 3 options. Celles-ci sont plus ou moins performantes, mais leurs possibilités sont différentes. Cet article passe rapidement en revue :

  • db_query
  • db_select
  • EntityFieldQuery

Utilisation de db_query

db_query est utilisé pour des requêtes statiques. Leur construction est de la forme :

$result = db_query("SELECT name, filename FROM {system} WHERE type = :type AND status = :status", array(':type' =>'module', ':status' =>1));

Au final, on écrit la requête SQL comme on l'aurait fait directement en ligne de commande, à la différence près que l'on peut utiliser des variables.

Exemple réel :
On veut récupérer l'identifiant, la ville, l'adresse, le nom et un lien dans une table de lieux, sur un type bien précis.

$dbresult = db_query("SELECT l.locid, l.city, l.name, l.address1, l.link  FROM {vcmlocation} l WHERE l.type = :type ORDER BY l.city, l.name ASC", array(':type' => $vcmlocation));

$dbresult est alors un tableau d'objets. Les champs peuvent être récupérés dans une boucle foreach par exemple :

  $rows=array();
  foreach ( $dbresult as $record) {
      $rows[] = array(
        array('data'=>  $record->city),
        array('data'=>l($record->name,'vcmlocation/'.$record->locid)),
        array('data'=>  $record->address1)
      );

La requête SQL générée par Drupal est la suivante :

SELECT l.locid, l.city, l.name, l.address1, l.link FROM vcmlocation l WHERE l.type = :type ORDER BY l.city, l.name ASC

 

Temps d'exécution : 0.17 à 0.21 ms

Utilisation de db_select

db_select est utilisé pour des requêtes dynamiques. On peut lui passer plusieurs options, une fois la requête déclarée. De plus, il n'est pas nécessaire de connaître la syntaxe SQL.
Plus d'informations sur http://drupal.org/node/310075
Exemple :

  $query = db_select('vcmlocation', 'l');
  $query->fields('l', array('locid', 'city', 'name', 'address1', 'link','type'));
  $query->orderBy('l.city, l.name', 'ASC');
  $query->condition('l.type', $vcmlocation, '=');

Requête SQL correspondante :

 
	SELECT l.locid AS locid, l.city AS city, l.name AS name, l.address1 AS address1, l.link AS link, l.type AS type FROM vcmlocation l WHERE (l.type = :db_condition_placeholder_0) ORDER BY l.city, l.name ASC

Temps d'exécution : 0.22 à 0.62 ms

Utilisation de EntityFieldQuery

Drupal 7 a introduit les entités qui permettent de gérer des types d'objets. On dispose alors d'une nouvelle possibilité de réaliser des requêtes, ceci sans préciser de syntaxe SQL. Le gros avantage de EntityFieldQuery c'est qu'on peut récupérer également des champs attachés à l'objet, puisqu'on travaille sur les entités. On peut également préciser des conditions sur ces champs. Exemple de construction :

  $query = new EntityFieldQuery();
  $entities = $query->entityCondition('entity_type', 'node')
                    ->entityCondition('bundle', 'event')
                    ->propertyCondition('status', 1)
                    ->fieldCondition('field_date', 'value', array('2011-03-01', '2011-03-31'), 'BETWEEN')
                    ->fieldOrderBy('field_date', 'value', 'ASC')
                    ->execute();

  $nodes = node_load_multiple(array_keys($entities['node']));
  $views = node_view_multiple($nodes, 'teaser');
  $build['#nodes'] = $views['nodes'];
  $build['#theme'] = 'whatever';

  return $build;

Exemple réel, toujours sur les mêmes données

  $query = new EntityFieldQuery();

  $query->entityCondition('entity_type', 'vcmlocation')
    ->propertyCondition('type', $vcmlocation)
    ->propertyOrderBy('city', 'ASC') ; 

  $result = $query->execute();

  if (isset($result['vcmlocation'])) {
  $news_items_nids = array_keys($result['vcmlocation']);
  $dbresult = vcmlocation_load_multiple($news_items_nids);
  }

Drupal génère deux requêtes SQL :

SELECT vcmlocation.locid AS entity_id, vcmlocation.type AS bundle, :entity_type AS entity_type, NULL AS revision_id FROM vcmlocation vcmlocation WHERE (vcmlocation.type = :db_condition_placeholder_0) ORDER BY vcmlocation.city ASC

SELECT base.locid AS locid, base.type AS type, base.name AS name, base.address1 AS address1, base.address2 AS address2, base.address3 AS address3, base.city AS city, base.zipcode AS zipcode, base.telephone AS telephone, base.link AS link, base.comments AS comments, base.created AS created, base.changed AS changed FROM vcmlocation base WHERE (base.locid IN (:db_condition_placeholder_0, :db_condition_placeholder_1, :db_condition_placeholder_2, :db_condition_placeholder_3)) 

La première requête correspond au query->execute : elle récupère la liste des ID des entités correspondant aux conditions.
La deuxième requête correspond au load_multiple sur l'entité.
Temps des requêtes : entre 0.22 et 0.65 ms pour la première, 0.23 et 0.62 ms pour la deuxième.

Conclusion

Selon le type de requête (SELECT uniquement), Drupal propose des solutions assez différentes. Pour des besoins très basiques, db_query reste intéressant, à condition de connaître la syntaxe SQL. Pour des besoins plus évolués et sans syntaxe SQL, db_select est une option rapide à mettre en oeuvre. Toutes les deux sont intéressantes si on veut récupérer des informations de la table de base de l'entité, sans devoir forcément charger tous les champs.

Si la requête doit également porter sur des champs ajoutés à l'entité, il faut passer par EntityFieldQuery, en notant également que l'on peut définir une fonction spécifique qui hérite de cet objet, afin de fixer certaines options par défaut par exemple.

Catégorie