Je suis un débutant admis à l'API Entity, mais j'essaie de remédier à cela. Je travaille sur un site qui utilise un certain nombre de types de contenu avec différents champs attachés à eux; Rien d'extraordinaire. Donc, quand je veux récupérer un ensemble d'entrées, j'ai, dans mon ignorance, appelé directement dans la base de données et fait quelque chose comme ceci:
$query = db_select('node', 'n')->extend('PagerDefault');
$query->fields('n', array('nid'));
$query->condition('n.type', 'my_content_type');
$query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id');
$query->condition('role.field_user_role_value', $some_value);
$query->leftJoin('field_data_field_withdrawn_time', 'wt', 'n.nid = wt.entity_id');
$query->condition('wt.field_withdrawn_time_value', 0);
$query->orderBy('n.created', 'desc');
$query->limit(10);
$result = $the_questions->execute()->fetchCol();
(Oui, je pourrais probablement regrouper un tas de ces lignes en une seule $the_questions->
déclaration; veuillez ignorer cela pour l'instant.)
En essayant de réécrire cela avec EntityFieldQuery, je trouve:
$query = new EntityFieldQuery();
$query
->entityCondition('entity_type', 'node')
->entityCondition('bundle', 'my_content_type')
->fieldCondition('field_user_role', 'value', $some_value)
->fieldCondition('field_withdrawn_time', 'value', 0)
->propertyOrderBy('created', 'desc')
->pager(10);
$result = $query->execute();
if (isset($result['node'])) {
$result_nids = array_keys($result['node']);
}
else {
$result_nids = array();
}
ce qui me donne les résultats escomptés et est sûrement beaucoup plus joli.
Donc, maintenant je me pose des questions sur les performances. Pour commencer, je jette chacun de ces bits de code dans une for()
boucle stupide , capturant time()
avant et après l'exécution. J'exécute chaque version 100 fois sur une base de données pas très grande et j'obtiens quelque chose comme ceci:
- Version directe: 110 msec
- Version EFQ: 4943 msec
Évidemment, j'obtiens des résultats différents lorsque je relance le test, mais les résultats sont toujours dans le même stade.
Oui. Suis-je en train de faire quelque chose de mal ici, ou est-ce juste le coût d'utilisation de l'EFQ? Je n'ai effectué aucun réglage spécial de la base de données en ce qui concerne les types de contenu; ils sont juste ce qui vient de la définition des types de contenu de la manière habituelle, basée sur un formulaire. Des pensées? Le code EFQ est certainement plus propre, mais je ne pense vraiment pas pouvoir me permettre un rendement 40 fois supérieur.
->addTag('node_access')
dans la requête ??). J'ai relancé la requête "directe" avec une balise node_access, et les temps d'exécution sont beaucoup plus proches: le temps d'EFQ est maintenant seulement environ un facteur 2 supérieur à l'approche directe, ce qui semble raisonnable compte tenu du SQL relatif que les deux pompent (ce qui Je peux poster si les gens se soucient encore). (suite au commentaire suivant ....)Réponses:
La
EntityFieldQuery
classe est aussi efficace que ses exigences le lui permettent. Il doit être compatible avec toutes les classes de stockage de champ, même avec celles qui utilisent un moteur NoSQL pour stocker les données de champ, comme celle qui utilise MongoDB . Pour cette raison,EntityFieldQuery
ne peut pas interroger directement la base de données, car le backend de stockage de champ actuel peut ne pas utiliser du tout de base de données SQL.Même dans le cas où le stockage sur le terrain utilise un moteur SQL pour stocker ses données, l'équivalent de
$query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id'); $query->condition('role.field_user_role_value', $some_value);
pour laEntityFieldQuery
classe nécessite:La différence est immédiatement visible: dans un cas, vous utilisez trois chaînes littérales, tandis que dans l'autre, il existe un code qui (dans le plus simple des cas) concatène des chaînes.
Selon votre commentaire sur le code qui vérifie si l'utilisateur a l'autorisation d'accéder aux champs, vous pouvez contourner cela en utilisant la ligne suivante pour le code en utilisant la
EntityFieldQuery
classe.Cela fonctionne si vous utilisez Drupal 7.15 ou supérieur; pour les versions antérieures, vous devez utiliser le code suivant.
Comme d'habitude, vous ne devez pas contourner l'autorisation d'accès si le code peut montrer à l'utilisateur des informations auxquelles l'utilisateur ne devrait pas avoir accès. Ceci est similaire à ce qui est fait à partir de Drupal lorsqu'un nœud non publié n'est affiché qu'aux utilisateurs qui ont l'autorisation de voir les nœuds non publiés. Si le but du code est, par exemple, de sélectionner des entités qui sont supprimées successivement (par exemple pendant les tâches cron), le contournement du contrôle d'accès ne fait aucun mal et c'est la seule façon de procéder.
la source
->extend('PagerDefault');