Я новичок в Entity API, но пытаюсь это исправить. Я работаю над сайтом, который использует несколько типов контента с различными полями, прикрепленными к ним; ничего фантастического. Поэтому, когда я хочу получить набор записей, я по своему невежеству обращаюсь непосредственно к базе данных и делаю что-то вроде этого:
$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();
(да, я мог бы, вероятно, свести кучу этих строк в одно $the_questions->
утверждение; пока проигнорируйте это.)
Пытаясь переписать это с EntityFieldQuery, я придумываю:
$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();
}
что дает мне желаемый результат и, безусловно, намного красивее.
Итак, теперь я задаюсь вопросом о производительности. Для начала я добавляю каждый из этих битов кода в тупой for()
цикл, записывая time()
до и после выполнения. Я запускаю каждую версию 100 раз по не очень большой базе данных и получаю что-то вроде этого:
- Прямая версия: 110 мс
- Версия EFQ: 4943 мсек
Очевидно, что при повторном запуске теста я получаю разные результаты, но результаты постоянно находятся на одном уровне.
Хлоп. Я что-то здесь не так делаю, или это просто стоимость использования EFQ? Я не делал никакой специальной настройки базы данных в отношении типов контента; это именно то, что приходит от определения типов контента обычным, основанным на форме способом. есть идеи? Код EFQ определенно чище, но я действительно не думаю, что могу позволить себе 40-кратное снижение производительности.
->addTag('node_access')
в запросе ??). Я перезапускаю «прямой» запрос с тэгом node_access, и время выполнения намного ближе: время EFQ теперь только примерно в 2 раза больше, чем прямой подход, что выглядит разумно, учитывая относительный SQL, который выкачивают оба (что Я могу опубликовать, если люди все еще заботятся). (продолжение следующего комментария ....)Ответы:
EntityFieldQuery
Класс столь же эффективным , как его требования позволяют ему быть. Он должен быть совместим с любыми классами хранения полей, даже с теми, которые используют движок NoSQL для хранения полевых данных, такими как тот, который использует MongoDB . По этой причинеEntityFieldQuery
нельзя напрямую запрашивать базу данных, поскольку текущий сервер хранения полей может вообще не использовать базу данных SQL.Даже в том случае, если хранилище полей использует механизм SQL для хранения своих данных, эквивалент
$query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id'); $query->condition('role.field_user_role_value', $some_value);
дляEntityFieldQuery
класса требует:Разница сразу видна: в одном случае вы используете три литеральные строки, а в другом - код, который (в простейшем случае) объединяет строки.
Согласно вашему комментарию о коде, который проверяет, есть ли у пользователя разрешение на доступ к полям, вы можете обойти это, используя следующую строку, к коду, используя
EntityFieldQuery
класс.Это работает, если вы используете Drupal 7.15 или выше; для более ранних версий вы должны использовать следующий код.
Как обычно, вы не должны обходить разрешение на доступ, если код может показывать пользователю информацию, к которой у пользователя не должно быть доступа. Это похоже на то, что делается в Drupal, когда неопубликованный узел показывается только пользователям, которые имеют разрешение на просмотр неопубликованных узлов. Если целью кода является, например, выбор некоторых сущностей, которые удаляются последовательно (например, во время задач cron), то обход контроля доступа не причиняет никакого вреда, и это единственный способ продолжить.
источник
->extend('PagerDefault');
сначала я не заметил )