Ich bin ein zugelassener Neuling in der Entity-API, aber ich versuche, das zu heilen. Ich arbeite an einer Site, die eine Reihe von Inhaltstypen mit verschiedenen Feldern verwendet. Nichts Besonderes. Wenn ich also eine Reihe von Einträgen abrufen möchte, habe ich in meiner Unwissenheit direkt in die Datenbank aufgerufen und so etwas getan:
$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();
(Ja, ich könnte wahrscheinlich ein paar dieser Zeilen zu einer einzigen $the_questions->
Anweisung zusammenfassen. Bitte ignorieren Sie dies vorerst.)
Beim Versuch, dies mit EntityFieldQuery neu zu schreiben, habe ich Folgendes gefunden:
$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();
}
Das gibt mir die gewünschten Ergebnisse und ist sicherlich viel schöner.
Jetzt wundere ich mich über die Leistung. Zunächst werfe ich jedes dieser Codebits in eine blöde for()
Schleife und nehme sie time()
vor und nach der Ausführung auf. Ich führe jede Version 100 Mal über eine nicht sehr große Datenbank aus und erhalte so etwas:
- Direkte Version: 110 ms
- EFQ-Version: 4943 ms
Natürlich erhalte ich unterschiedliche Ergebnisse, wenn ich den Test erneut durchführe, aber die Ergebnisse befinden sich durchweg im selben Bereich.
Huch. Mache ich hier etwas falsch oder sind dies nur die Kosten für die Verwendung von EFQ? Ich habe keine spezielle Datenbankoptimierung in Bezug auf die Inhaltstypen durchgeführt. Sie sind genau das, was sich aus der Definition der Inhaltstypen auf die übliche, formularbasierte Weise ergibt. Irgendwelche Gedanken? Der EFQ-Code ist definitiv sauberer, aber ich glaube wirklich nicht, dass ich mir einen 40-fachen Leistungseinbruch leisten kann.
->addTag('node_access')
die Abfrage keine enthält ??). Ich habe die "direkte" Abfrage mit einem node_access-Tag erneut durchgeführt, und die Ausführungszeiten sind viel näher: Die Zeit von EFQ ist jetzt nur um den Faktor 2 größer als der direkte Ansatz, der angesichts der relativen SQL, die beide auspumpen (was vernünftig erscheint), vernünftig erscheint Ich kann posten, wenn sich die Leute noch darum kümmern. (Fortsetzung beim nächsten Kommentar ....)Antworten:
Die
EntityFieldQuery
Klasse ist so effizient, wie es ihre Anforderungen zulassen. Es muss mit allen Feldspeicherklassen kompatibel sein, auch mit solchen, die eine NoSQL-Engine zum Speichern der Felddaten verwenden, z. B. die, die MongoDB verwendet . Aus diesem GrundEntityFieldQuery
kann die Datenbank nicht direkt abgefragt werden, da das aktuelle Feldspeicher-Backend möglicherweise überhaupt keine SQL-Datenbank verwendet.Selbst wenn der Feldspeicher eine SQL-Engine zum Speichern seiner Daten verwendet, erfordert das Äquivalent
$query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id'); $query->condition('role.field_user_role_value', $some_value);
für dieEntityFieldQuery
Klasse:Der Unterschied ist sofort sichtbar: In einem Fall verwenden Sie drei Wurfzeichenfolgen, während es in dem anderen Fall Code gibt, der (im einfachsten Fall) Zeichenfolgen verkettet.
Gemäß Ihrem Kommentar zu Code, der prüft, ob der Benutzer die Berechtigung zum Zugriff auf die Felder hat, können Sie diesen mithilfe der folgenden Zeile mit der
EntityFieldQuery
Klasse an den Code umgehen .Dies funktioniert, wenn Sie Drupal 7.15 oder höher verwenden. Für frühere Versionen sollten Sie den folgenden Code verwenden.
Wie üblich sollten Sie die Zugriffsberechtigung nicht umgehen, wenn der Code den Benutzerinformationen anzeigen könnte, auf die der Benutzer keinen Zugriff haben sollte. Dies ähnelt der Vorgehensweise von Drupal, wenn ein unveröffentlichter Knoten nur den Benutzern angezeigt wird, die die Berechtigung haben, unveröffentlichte Knoten anzuzeigen. Wenn der Zweck des Codes beispielsweise darin besteht, einige Entitäten auszuwählen, die nacheinander gelöscht werden (z. B. während Cron-Aufgaben), schadet die Umgehung der Zugriffssteuerung nicht und ist die einzige Möglichkeit, fortzufahren.
quelle
->extend('PagerDefault');
zuerst nicht bemerkt )