Magento 1: Optimalisasi kinerja untuk menghapus entitas

10

Saat ini saya mencoba untuk meningkatkan beberapa modul mengenai kinerja.

Beberapa dari Anda mungkin tahu penggunaan walk()metode pengumpulan yang sangat berguna untuk menghindari perulangan melalui produk secara langsung.

Selain itu dan terima kasih kepada @Vinai, Anda juga dapat menggunakan delete()metode pengumpulan .

Tapi saya perhatikan bahwa file asli Magento 1 tidak selalu menggunakan metode apa pun untuk dihapus.

Salah satu kode terburuk yang pernah saya lihat adalah massDelete()metode dari app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.phpmana produk dimuat dalam satu lingkaran sebelum dihapus .

foreach ($productIds as $productId) {
    $product = Mage::getSingleton('catalog/product')->load($productId);
    Mage::dispatchEvent('catalog_controller_product_delete', array('product' => $product));
    $product->delete();
}

Jadi saya melakukan beberapa tes kinerja, menambahkan beberapa panggilan logging untuk memeriksa waktu yang dibutuhkan dan penggunaan memori untuk 100 penghapusan produk.

Tes 1: walkmetode

Saya mengganti kode asli yang disisipkan di atas dengan kode ini:

$collection = Mage::getResourceModel('catalog/product_collection')
                        ->addAttributeToSelect('entity_id')
                        ->addIdFilter($productIds)
                        ->walk('delete');

Dan hasil saya adalah sebagai berikut pada server dev jelek saya (rata-rata berdasarkan 10 tes):

  • Kode asli: 19,97 detik, 15,84 MB digunakan
  • Kode khusus: 17.12 detik, 15.45MB digunakan

Jadi untuk penghapusan 100 produk, kode khusus saya adalah 3 detik lebih cepat dan menggunakan 0.4MB lebih sedikit.

Tes 2: Menggunakan delete()metode pengumpulan

Saya mengganti kode asli dengan yang ini:

$collection = Mage::getResourceModel('catalog/product_collection')
                        ->addAttributeToSelect('entity_id')
                        ->addIdFilter($productIds)
                        ->delete();

Dan mind blown di sini adalah hasilnya:

  • Kode asli: 19,97 detik, 15,84 MB digunakan
  • Kode khusus: 1,24 detik, 6,34MB digunakan

Jadi untuk penghapusan 100 produk, kode khusus saya adalah 18 detik lebih cepat dan menggunakan 9MB lebih sedikit.

Seperti yang dinyatakan dalam komentar, sepertinya metode ini tidak memicu peristiwa Magento (setelah memuat, setelah menghapus) atau indeks / cache flush.

Pertanyaan

Jadi pertanyaan saya adalah: adakah alasan mengapa tim inti Magento tidak menggunakan walk('delete')atau bahkan lebih baik menggunakan delete()metode pengumpulan daripada memuat produk dalam satu lingkaran (yang kita semua tahu adalah praktik yang sangat sangat buruk)?

Tujuan utamanya adalah untuk mengetahui poin-poin penting tersebut dalam kasus pengembangan modul: apakah ada kasus tertentu di mana seseorang tidak dapat menggunakan metode walk/ collection delete()?

SUNTING: alasannya jelas bukan karena catalog_controller_product_deleteperistiwa yang dikirim karena kode yang sama dapat ditemukan di beberapa tempat (periksa massDeletemetode) di inti Magento. Saya telah menggunakan contoh produk untuk menyoroti kinerja karena biasanya merupakan entitas terbesar

Raphael di Digital Pianism
sumber
3
Saya kira itu karena acara tersebut. Tapi saya setuju dengan Anda, itu gaya yang buruk, terutama penggunaan getSingleton()sebagai ukuran kinerja, bukan penggunaan koleksi yang jelas. Oh dan itu mungkin untuk memicu acara dengan koleksi juga, hanya saja tidak dengan jalan walk()pintas.
Fabian Schmengler
1
@fschmengler ya saya memikirkan acara itu juga, tetapi seperti yang saya katakan di edit saya, itu terjadi di banyak tempat di mana tidak ada acara yang dikirim.
Raphael di Digital Pianism
3
Tidak mengherankan. delete()membuat kueri HAPUS alih-alih memuat koleksi dan menghapus setiap produk. Dengan itu Anda akan benar-benar kehilangan acara.
Fabian Schmengler
5
@fschmengler Hapus koleksi juga menghapus setiap item individual, tetapi mem-bypass kliring cache dan memicu beberapa peristiwa magento dan pengindeks. Dari situlah perbedaan harus datang.
Vinai
2
@Vinai kamu benar. Wishful thinking di pihak saya
Fabian Schmengler

Jawaban:

4

Jadi saya melakukan beberapa tes kinerja, menambahkan beberapa panggilan logging untuk memeriksa waktu yang dibutuhkan dan penggunaan memori untuk 100 penghapusan produk

Catatan, tetapi Anda harus melihat menggunakan Varien Profiler untuk ini!

kode khusus saya lebih cepat 2 detik dan lebih sedikit menggunakan 0.4MB

Meskipun saya tidak ragu bahwa perubahan Anda akan meningkatkan kinerja, akan berguna untuk memberikan hasil "sebelum" untuk membandingkan peningkatan.

apakah ada alasan mengapa tim inti Magento tidak menggunakan walk('delete')alih - alih memuat produk dalam satu lingkaran (yang kita semua tahu adalah praktik yang sangat sangat buruk)?

Nah, kita tahu dari pertanyaan lain di forum ini sebagai berikut:

  • Basis kode Magento telah berkembang dan berkembang selama bertahun-tahun
  • Sudah banyak pengembang yang mengerjakannya
  • Proses alur kerja pengembangan inti Magento telah meningkat secara dramatis dari waktu mereka bekerja pada platform, mengejar ketinggalan dengan praktik terbaik dan teknik modern hingga titik di mana Magento 2 sekarang menunjukkan banyak praktik desain aplikasi modern terkemuka

Jadi saya akan menyarankan bahwa contoh yang Anda temukan mungkin adalah salah satu dari banyak permata yang berpotensi tersembunyi dalam kode yang telah ditulis sebelumnya, dan / atau oleh pengembang yang kurang berpengalaman. Seperti banyak kode inti (dan kode komunitas!) Itu akan diuji pada kumpulan data kecil dan tidak diuji pertempuran, sehingga kinerja mungkin tidak dipantau secara ketat.

Apakah peningkatan Anda bermanfaat, dan lebih selaras dengan praktik terbaik daripada kode asli? Iya. Anda sebagai pengembang Magento [1.x] komunitas namun tidak memiliki kemampuan untuk berkontribusi perbaikan yang disarankan meskipun seperti yang Anda lakukan dengan Magento 2, jadi saran saya akan menerapkan ini dalam modul lokal jika Anda memerlukannya untuk kinerja di salah satu toko Anda , atau abaikan saja jika itu tidak memengaruhi Anda tetapi Anda menyadarinya saat melakukan riset.

Sebagai pembaruan pada edit pertanyaan Anda, saya yakin Anda mengetahui bahwa metode jalan di Varien_Data_Collection menerima panggilan balik sewenang-wenang, jadi Anda akan bebas menggunakannya untuk apa pun yang Anda inginkan. Untuk mengirim acara dalam contoh asli Anda bisa melakukannya dengan fungsi jalan kaki, serta menghapus.

Satu-satunya alasan saya bisa membayangkan bahwa memuat produk sebelum menghapusnya akan berguna mungkin karena pengamat yang melekat pada acara itu mungkin memerlukan set data lengkap tidak tersedia tanpa memuat produk terlebih dahulu. Jika itu masalahnya, itu akan menjelaskan mengapa mereka menggunakan singleton daripada model untuk setidaknya meminimalkan overhead objek.

Robbie Averill
sumber
Terima kasih, saya telah menambahkan hasil sebelum dan sesudah posting. Jadi Anda pikir tidak ada alasan khusus selain dari fakta bahwa itu kode lama?
Raphael di Digital Pianism
2
Itu dugaanku, ya. Memuat produk sebelum menghapusnya tidak ada manfaatnya selain menembakkan peristiwa pemuatan, yang tidak relevan untuk dihapus. Biasanya Anda memuat produk untuk mendapatkan set data lengkapnya, yang mungkin diperlukan untuk salah satu pengamat yang melekat pada acara tersebut - jika itu masalahnya akan menjelaskan mengapa mereka menggunakan singleton bukan model.
Robbie Averill
1
Lihat hasil edit saya dengan lebih banyak tes, hasilnya bahkan lebih gila
Raphael di Digital Pianism
0

catalog_controller_product_deletePemikir saya adalah mereka melakukannya untuk memecat acara yang sedang digunakan oleh Mage_Tag.

catalog_product_delete_before atau catalog_product_delete_after akan berarti ini tidak perlu meskipun saya akan berpikir. Bertanya-tanya apakah acara khusus ini juga digunakan untuk pencatatan tindakan Admin.

Daniel Kenney
sumber
Memikirkan hal itu juga, tetapi itu jelas bukan alasan karena itu juga terjadi pada massDelete()aksiCustomerController.php
Raphael di Digital Pianism
Lihat hasil edit saya dengan lebih banyak tes, hasilnya lebih gila
Raphael di Digital Pianism
0

Saya pikir penghapusan massal harus berfungsi seperti menghapus satu produk (terisi penuh).

Untuk $collection->delete()jawabannya sudah diberikan. Jika Anda tidak memicu deleter_before, delete_aftersaya mungkin dapat merusak beberapa ekstensi dan akan memotong beberapa pengamat yang digunakan dalam inti.

$collection->walk('delete')mungkin bekerja, tetapi masih memiliki kelemahan bahwa data produk tidak lengkap. Ini juga dapat merusak pengamat khusus jika mereka bergantung pada data tambahan, misalnya objek item persediaan.

Saya kira, jika Anda mengubah ->addAttributeToSelect('entity_id')ke ->addAttributeToSelect('*')dan add->setFlag('require_stock_items', true) (untuk menambahkan data stok produk) tidak akan melakukan lebih baik maka "loop-delete".

Sepertinya gaya yang buruk, tapi saya pikir itu tepat untuk kedua tindakan penghapusan massal.

Saya menggunakan walk()dan delete()untuk model khusus juga, tetapi saya tahu bahwa tidak ada pengamat atau entity_idcukup. Hanya untuk menyebutkan, walk()akan bekerja dengan semua acara yang digunakan dalam inti, karena hanya digunakan $product->getId(), tetapi Anda tidak tahu tentang pengamat pihak ke-3.

sv3n
sumber