Sou um novato admitido na API de entidades, mas estou tentando curar isso. Estou trabalhando em um site que usa vários tipos de conteúdo com vários campos anexados a eles; nada chique. Portanto, quando quero recuperar um conjunto de entradas, na minha ignorância, liguei diretamente para o banco de dados e fiz algo assim:
$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();
(sim, eu provavelmente poderia recolher várias dessas linhas em uma única $the_questions->
declaração; por favor, ignore isso por enquanto.)
Tentando reescrever isso com EntityFieldQuery, eu venho com:
$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();
}
o que me dá os resultados desejados e é certamente muito mais bonito.
Então, agora estou me perguntando sobre desempenho. Para começar, jogo cada um desses bits de código em um for()
loop estúpido , capturando time()
antes e depois da execução. Eu executo cada versão 100 vezes em um banco de dados não muito grande e obtenho algo assim:
- Versão direta: 110 ms
- Versão EFQ: 4943 ms
Obviamente, obtenho resultados diferentes quando refiz o teste, mas os resultados estão consistentemente no mesmo estádio.
Caramba. Estou fazendo algo errado aqui, ou isso é apenas o custo do EFQ? Eu não fiz nenhum ajuste especial no banco de dados com relação aos tipos de conteúdo; são exatamente o que vem da definição dos tipos de conteúdo da maneira usual e baseada em formulários. Alguma ideia? O código EFQ é definitivamente mais limpo, mas eu realmente não acho que posso pagar um desempenho de 40x.
->addTag('node_access')
na consulta ??). Eu redireciono a consulta "direta" com uma tag node_access, e os tempos de execução são muito mais próximos: o tempo do EFQ agora é apenas um fator 2 maior que a abordagem direta, o que parece razoável, considerando o SQL relativo que ambos estão produzindo (o que Posso postar se as pessoas ainda se importam). (continua na próxima comentário ....)Respostas:
A
EntityFieldQuery
classe é tão eficiente quanto seus requisitos o permitem. Ele precisa ser compatível com qualquer classe de armazenamento de campo, mesmo com aquelas que usam um mecanismo NoSQL para armazenar os dados de campo, como o que usa o MongoDB . Por esse motivo,EntityFieldQuery
não é possível consultar diretamente o banco de dados, porque o backend de armazenamento de campo atual pode não usar um banco de dados SQL.Mesmo no caso de o armazenamento em campo usar um mecanismo SQL para armazenar seus dados, o equivalente
$query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id'); $query->condition('role.field_user_role_value', $some_value);
a daEntityFieldQuery
classe exige:A diferença é imediatamente visível: em um caso, você está usando três cadeias de caracteres literais, enquanto no outro caso há um código que (no mais simples dos casos) está concatenando cadeias de caracteres.
Conforme seu comentário sobre o código que verifica se o usuário tem permissão para acessar os campos, você pode ignorá-lo usando a linha a seguir no código usando a
EntityFieldQuery
classeIsso funciona se você estiver usando o Drupal 7.15 ou superior; para versões anteriores, você deve usar o seguinte código.
Como de costume, você não deve ignorar a permissão de acesso se o código puder mostrar às informações do usuário às quais o usuário não deve ter acesso. Isso é semelhante ao que é feito no Drupal quando um nó não publicado é mostrado apenas aos usuários que têm permissão para ver nós não publicados. Se o objetivo do código é, por exemplo, selecionar algumas entidades que são excluídas sucessivamente (por exemplo, durante tarefas cron), ignorar o controle de acesso não causa nenhum dano e é a única maneira de prosseguir.
fonte
->extend('PagerDefault');
em primeiro lugar)