EntityFieldQuery가 실제로이 비효율적입니까?


11

엔터티 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->문 으로 축소 할 수 있습니다. 지금은 pls를 무시하십시오.)

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 번 실행하고 다음과 같은 것을 얻습니다.

  • 직접 버전 : 110msec
  • EFQ 버전 : 4943msec

테스트를 다시 실행할 때 분명히 다른 결과를 얻지 만 결과는 동일한 야구장에서 일관되게 나타납니다.

Yikes. 내가 여기서 잘못하고 있습니까, 아니면 EFQ를 사용하는 비용입니까? 컨텐츠 유형과 관련하여 특별한 데이터베이스 조정을 수행하지 않았습니다. 이들은 일반적인 양식 기반 방식으로 컨텐츠 유형을 정의하는 것에서 나온 것입니다. 이견있는 사람? EFQ 코드는 확실히 더 깨끗하지만 40 배의 성능 저하를 감당할 수 없다고 생각합니다.


3
생성 된 SQL 쿼리를 모두 덤프 할 수 있습니까?
Andre Baumeier

1
참조 이 하나 확실 EFQ의 SQL을 얻는 방법을하지 않은 경우
클라이브

2
진행 상황은 다음과 같습니다. 여기서 진행중인 작업은 쿼리 크기가 상당히 증가하는 노드 액세스 규칙이 많이 있다는 것입니다. 그것들은 EFQ 쿼리에 자동으로 적용되었습니다 (쿼리가 없더라도 ->addTag('node_access')??). node_access 태그를 사용하여 "직접"쿼리를 다시 실행하면 실행 시간이 훨씬 더 가깝습니다. EFQ의 시간은 이제 직접 접근보다 2 배 정도 더 큽니다. 사람들이 여전히 신경 쓰면 게시 할 수 있습니다). (다음 댓글에 계속 ....)
Jim Miller

이제 질문은 EFQ 버전에서 node_access를 자동으로 얻는 이유입니다. addTag () 절을 통해 명시 적으로 요청해야한다고 생각 했습니까 ??
Jim Miller

답변:


10

EntityFieldQuery클래스는 요구 사항만큼 효율적입니다. MongoDB를 사용하는 것과 같은 NoSQL 엔진을 사용하여 필드 데이터를 저장하는 클래스와도 모든 필드 스토리지 클래스와 호환되어야합니다 . 이러한 이유로 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클래스 를 사용하여 다음 줄을 사용하여 코드를 무시할 수 있습니다 .

$query->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');

Drupal 7.15 이상을 사용하는 경우 작동합니다. 이전 버전의 경우 다음 코드를 사용해야합니다.

$account = user_load(1);
$query->addMetaData('account', $account);

평소와 같이, 코드가 사용자에게 액세스 권한이 없어야하는 정보를 사용자에게 표시 할 수있는 경우 액세스 권한을 우회해서는 안됩니다. 이는 공개되지 않은 노드가 공개되지 않은 노드를 볼 수있는 권한이있는 사용자에게만 표시 될 때 Drupal에서 수행 된 것과 유사합니다. 코드의 목적이 예를 들어, 연속적으로 삭제되는 일부 엔티티 (예 : cron 작업 중)를 선택하는 경우 액세스 제어를 우회해도 아무런 해를 끼치 지 않으며 진행하는 유일한 방법입니다.


나는 첫 번째 쿼리는 호출기를 사용하기 때문에, 너무 (내가 알 didnt는하지 못했습니다 아마 나는 인정한다 ->extend('PagerDefault');처음을)
mojzis

당신이 맞아요
kiamlaluno

이것은 나에게 정말로 관심이있어서, 위의 실험 라인을 따라 무언가를 시도하고 있으며 숫자의 큰 차이를 확인할 수 없습니다 ... 누군가도 그것을 시도 할 수 있습니까?
mojzis

따라서 확인하기 만하면됩니다. 위에서 설명한대로 EFQ 호출은 사이트의 노드 액세스 규칙을 실행하지 않는 한 항상 사이트의 노드 액세스 규칙을 호출합니다. 권리?
Jim Miller

@JimMiller 맞습니다. 이것이 "DANGEROUS_ACCESS_CHECK_OPT_OUT"태그가 Drupal 7.15에 추가 된 이유입니다.
kiamlaluno
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.