Apakah EntityFieldQuery benar-benar tidak efisien ini?


11

Saya seorang pemula yang diakui untuk API Entity, tetapi saya mencoba untuk menyembuhkannya. Saya sedang mengerjakan situs yang menggunakan sejumlah tipe konten dengan berbagai bidang yang menyertainya; tidak ada yang mewah. Jadi, ketika saya ingin mengambil satu set entri, saya, dalam ketidaktahuan saya, memanggil langsung ke dalam database dan melakukan sesuatu seperti ini:

$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();

(ya, saya mungkin bisa menciutkan banyak baris ini menjadi satu $the_questions->pernyataan; tolong abaikan itu untuk sekarang.)

Mencoba menulis ulang ini dengan EntityFieldQuery, saya datang dengan:

$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();
}

yang memberi saya hasil yang diinginkan dan pasti jauh lebih cantik.

Jadi, sekarang saya bertanya-tanya tentang kinerja. Sebagai permulaan, saya membuang masing-masing bit kode ke dalam for()loop bodoh , menangkap time()sebelum dan sesudah eksekusi. Saya menjalankan setiap versi 100 kali melalui basis data yang tidak terlalu besar, dan mendapatkan sesuatu seperti ini:

  • Versi langsung: 110 msec
  • Versi EFQ: 4943 msec

Jelas saya mendapatkan hasil yang berbeda ketika saya menjalankan kembali tes, tetapi hasilnya konsisten di stadion baseball yang sama.

Astaga. Apakah saya melakukan sesuatu yang salah di sini, atau ini hanya biaya menggunakan EFQ? Saya belum melakukan penyetelan basis data khusus sehubungan dengan jenis konten; mereka hanya apa yang datang dari mendefinisikan tipe konten dengan cara biasa, berbasis form. Adakah pikiran? Kode EFQ jelas lebih bersih, tapi saya benar-benar tidak berpikir saya mampu menghasilkan hit kinerja 40x.


3
dapatkah Anda membuang kedua kueri sql yang dihasilkan?
Andre Baumeier

1
Lihat yang ini jika Anda tidak yakin bagaimana cara mengeluarkan SQL dari EFQ
Clive

2
OK, ada kemajuan: Apa yang terjadi di sini adalah bahwa situs saya memiliki banyak aturan akses simpul yang sedikit meningkatkan ukuran kueri. Itu diterapkan secara otomatis ke kueri EFQ (meskipun tidak ada ->addTag('node_access')dalam kueri ??). Saya mengulangi permintaan "langsung" dengan tag node_access, dan waktu eksekusi lebih dekat: Waktu EFQ sekarang hanya sekitar faktor 2 lebih besar daripada pendekatan langsung, yang terlihat masuk akal mengingat SQL relatif yang keduanya pompakan (yang Saya dapat memposting jika orang masih peduli). (cont'd pada komentar berikutnya ....)
Jim Miller

Jadi sekarang pertanyaannya, saya kira, mengapa saya secara otomatis mendapatkan barang node_access dalam versi EFQ? Saya pikir Anda harus meminta secara eksplisit melalui klausa addTag () ??
Jim Miller

Jawaban:


10

The EntityFieldQuerykelas seefisien persyaratan memungkinkan hal itu terjadi. Itu harus kompatibel dengan kelas penyimpanan bidang apa pun, bahkan dengan mereka yang menggunakan mesin NoSQL untuk menyimpan data lapangan, seperti yang menggunakan MongoDB . Karena alasan itu, EntityFieldQuerytidak dapat secara langsung menanyakan database, karena backend penyimpanan bidang saat ini mungkin tidak menggunakan database SQL sama sekali.

Bahkan dalam kasus penyimpanan lapangan menggunakan mesin SQL untuk menyimpan datanya, setara dengan $query->leftJoin('field_data_field_user_role', 'role', 'n.nid = role.entity_id'); $query->condition('role.field_user_role_value', $some_value);untuk EntityFieldQuerykelas membutuhkan:

  • Kode untuk membangun nama tabel database dari nama bidang
  • Kode untuk membangun kondisi yang digunakan untuk bergabung dengan tabel yang berisi data lapangan dengan tabel yang berisi data entitas
  • Kode untuk membangun nama baris basis data yang berisi data bidang

Perbedaannya langsung terlihat: Dalam satu kasus Anda menggunakan tiga string litteral, sedangkan dalam kasus lain ada kode yang (dalam kasus paling sederhana) adalah string yang menyambung.

Sesuai komentar Anda tentang kode yang memeriksa apakah pengguna memiliki izin untuk mengakses bidang, Anda dapat memotongnya menggunakan baris berikut ke kode menggunakan EntityFieldQuerykelas.

$query->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');

Ini berfungsi jika Anda menggunakan Drupal 7.15, atau lebih tinggi; untuk versi sebelumnya, Anda harus menggunakan kode berikut.

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

Seperti biasa, Anda tidak boleh melewati izin akses jika kode dapat menunjukkan informasi pengguna yang tidak boleh diakses oleh pengguna. Ini mirip dengan apa yang dilakukan dari Drupal ketika simpul yang tidak diterbitkan hanya ditampilkan kepada pengguna yang memiliki izin untuk melihat simpul yang tidak diterbitkan. Jika tujuan kode adalah, misalnya, memilih beberapa entitas yang dihapus secara berurutan (misalnya selama tugas cron), maka dengan melewati kontrol akses tidak membahayakan, dan itu adalah satu-satunya cara untuk melanjutkan.


saya harus mengakui saya mungkin tidak benar, karena permintaan pertama menggunakan pager juga (saya tidak melihat ->extend('PagerDefault');pada awalnya)
mojzis

Aduh, kau benar.
kiamlaluno

ini membuat saya sangat tertarik, jadi saya mencoba sesuatu sesuai dengan percobaan di atas dan tidak dapat mengkonfirmasi perbedaan besar dalam jumlah ... bisakah seseorang mencobanya juga, tolong?
mojzis

Jadi, hanya untuk mengonfirmasi: Panggilan EFQ SELALU memohon aturan akses simpul situs kecuali Anda melakukan sesuatu untuk mencegah hal itu terjadi (seperti dijelaskan di atas). Baik?
Jim Miller

@JimMiller Itu benar, dan itulah alasan mengapa tag "DANGEROUS_ACCESS_CHECK_OPT_OUT" telah ditambahkan ke Drupal 7.15.
kiamlaluno
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.