Soy un novato admitido en la API de Entity, pero estoy tratando de curar eso. Estoy trabajando en un sitio que usa varios tipos de contenido con varios campos adjuntos; nada sofisticado. Entonces, cuando quiero recuperar un conjunto de entradas, he estado, en mi ignorancia, llamando directamente a la base de datos y haciendo algo como esto:
$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();
(sí, probablemente podría colapsar un montón de estas líneas en una sola $the_questions->
declaración; por favor, ignore eso por ahora).
Intentando reescribir esto con EntityFieldQuery, se me ocurre:
$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();
}
lo que me da los resultados deseados y seguramente es mucho más bonito.
Entonces, ahora me pregunto sobre el rendimiento. Como comienzo, lanzo cada uno de esos bits de código en un for()
bucle estúpido , capturando time()
antes y después de la ejecución. Ejecuto cada versión 100 veces sobre una base de datos no muy grande, y obtengo algo como esto:
- Versión directa: 110 ms
- Versión EFQ: 4943 ms
Obviamente obtengo resultados diferentes cuando vuelvo a ejecutar la prueba, pero los resultados están consistentemente en el mismo estadio.
Yikes ¿Estoy haciendo algo mal aquí, o es solo el costo de usar EFQ? No he realizado ningún ajuste especial de la base de datos con respecto a los tipos de contenido; son justo lo que viene de definir los tipos de contenido de la forma habitual basada en formularios. ¿Alguna idea? El código EFQ es definitivamente más limpio, pero realmente no creo que pueda permitirme un éxito de rendimiento 40x.
->addTag('node_access')
en la consulta ??). Volví a realizar la consulta "directa" con una etiqueta node_access, y los tiempos de ejecución están mucho más cerca: el tiempo de EFQ ahora es solo un factor 2 mayor que el enfoque directo, lo que parece razonable dado el SQL relativo que ambos están bombeando (que Puedo publicar si a la gente todavía le importa). (continúa en el siguiente comentario ...)Respuestas:
La
EntityFieldQuery
clase es tan eficiente como sus requisitos lo permiten. Debe ser compatible con cualquier clase de almacenamiento de campo, incluso con aquellos que usan un motor NoSQL para almacenar los datos de campo, como el que usa MongoDB . Por esa razón,EntityFieldQuery
no se puede consultar directamente la base de datos, ya que el backend de almacenamiento de campo actual podría no utilizar una base de datos SQL.Incluso en el caso de que el almacenamiento de campo utilice un motor SQL para almacenar sus datos, el equivalente de
$query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id'); $query->condition('role.field_user_role_value', $some_value);
laEntityFieldQuery
clase requiere:La diferencia es inmediatamente visible: en un caso está utilizando tres cadenas literales, mientras que en el otro caso hay un código que (en el caso más simple) está concatenando cadenas.
Según su comentario sobre el código que verifica si el usuario tiene permiso para acceder a los campos, puede omitir eso usando la siguiente línea al código usando la
EntityFieldQuery
clase.Esto funciona si está utilizando Drupal 7.15 o superior; para versiones anteriores, debe usar el siguiente código.
Como de costumbre, no debe omitir el permiso de acceso si el código puede mostrar al usuario información a la que el usuario no debería tener acceso. Esto es similar a lo que se hace desde Drupal cuando un nodo no publicado solo se muestra a los usuarios que tienen permiso para ver nodos no publicados. Si el propósito del código es, por ejemplo, seleccionar algunas entidades que se eliminan sucesivamente (por ejemplo, durante las tareas cron), eludir el control de acceso no causa ningún daño, y es la única forma de proceder.
fuente
->extend('PagerDefault');
al principio)