Magento 1: Tối ưu hóa hiệu suất để xóa các thực thể


10

Tôi hiện đang cố gắng cải thiện một vài mô-đun về hiệu suất.

Một số bạn có thể biết cách sử dụng walk()phương pháp trên bộ sưu tập rất hữu ích để tránh lặp trực tiếp qua các sản phẩm.

Trên hết và nhờ @Vinai, người ta cũng có thể sử dụng delete()phương pháp thu thập .

Nhưng tôi nhận thấy rằng các tệp gốc Magento 1 không luôn sử dụng bất kỳ phương thức nào để xóa.

Một trong những mã tồi tệ nhất tôi thấy là massDelete()phương thức app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.phpcác sản phẩm được tải trong một vòng lặp trước khi xóa .

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

Vì vậy, tôi đã thực hiện một số kiểm tra hiệu suất, thêm một số cuộc gọi đăng nhập để kiểm tra thời gian thực hiện và việc sử dụng bộ nhớ cho 100 sản phẩm bị xóa.

Kiểm tra 1: walkphương pháp

Tôi đã thay thế mã gốc được dán ở trên bằng mã này:

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

Và kết quả của tôi là như sau trên máy chủ dev crappy của tôi (trung bình dựa trên 10 bài kiểm tra):

  • Mã gốc: 19,97 giây, sử dụng 15,84 MB
  • Mã tùy chỉnh: 17,12 giây, sử dụng 15,45 MB

Vì vậy, đối với việc xóa 100 sản phẩm, mã tùy chỉnh của tôi nhanh hơn 3 giây và sử dụng ít hơn 0,4 MB.

Kiểm tra 2: Sử dụng delete()phương pháp thu thập

Tôi đã thay thế mã ban đầu bằng mã này:

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

tâm trí thổi vào đây là kết quả:

  • Mã gốc: 19,97 giây, sử dụng 15,84 MB
  • Mã tùy chỉnh: 1,24 giây, 6,34 MB được sử dụng

Vì vậy, đối với việc xóa 100 sản phẩm, mã tùy chỉnh của tôi nhanh hơn 18 giây và sử dụng ít hơn 9MB.

Như đã nêu trong các bình luận, có vẻ như phương pháp này không kích hoạt các sự kiện Magento (sau khi tải, sau khi xóa) cũng như xóa chỉ mục / bộ đệm.

Câu hỏi

Vì vậy, câu hỏi của tôi là: có lý do tại sao nhóm nòng cốt Magento không sử dụng phương pháp walk('delete')thu thập hay sự kiện tốt hơn delete()thay vì tải sản phẩm trong một vòng lặp (mà tất cả chúng ta đều biết là một thực tiễn rất xấu)?

Mục tiêu chính là nhận thức được những điểm chính như vậy trong trường hợp phát triển mô-đun: có trường hợp cụ thể nào mà người ta không thể sử dụng phương pháp walk/ bộ sưu tập delete()không?

EDIT: lý do chắc chắn không phải vì catalog_controller_product_deletesự kiện được gửi đi vì cùng một mã có thể được tìm thấy ở một số nơi (kiểm tra các massDeletephương thức) trong lõi Magento. Tôi đã sử dụng ví dụ về các sản phẩm để làm nổi bật hiệu suất vì chúng thường là các thực thể lớn nhất


3
Tôi đoán đó là vì sự kiện này. Nhưng tôi đồng ý với bạn, đó là phong cách tồi tệ, đặc biệt là việc sử dụng getSingleton()làm thước đo hiệu suất, thay vì sử dụng bộ sưu tập rõ ràng. Ồ và cũng có thể kích hoạt sự kiện bằng một bộ sưu tập, nhưng không phải bằng walk()phím tắt.
Fabian Schmengler

1
@fschmengler yeah Tôi cũng nghĩ về sự kiện này nhưng như tôi đã nói trong bản chỉnh sửa của mình, nó xảy ra ở rất nhiều nơi mà không có sự kiện nào được gửi đi.
Raphael tại Nghệ thuật piano kỹ thuật số

3
Không đáng ngạc nhiên. delete()tạo một truy vấn XÓA thay vì tải bộ sưu tập và xóa từng sản phẩm. Với điều đó bạn sẽ thực sự mất các sự kiện.
Fabian Schmengler

5
@fschmengler Một bộ sưu tập xóa cũng thực hiện xóa cho từng mục riêng lẻ, nhưng nó bỏ qua việc xóa bộ nhớ cache và kích hoạt một số sự kiện magento và bộ chỉ mục. Đó là nơi mà sự khác biệt phải đến từ.
Vinai

2
@Vinai bạn nói đúng. Suy nghĩ mong muốn về phía tôi
Fabian Schmengler

Câu trả lời:


4

Vì vậy, tôi đã thực hiện một số kiểm tra hiệu suất, thêm một số cuộc gọi đăng nhập để kiểm tra thời gian thực hiện và việc sử dụng bộ nhớ cho 100 sản phẩm bị xóa

Lưu ý bên lề, nhưng bạn nên xem xét việc sử dụng Varien Profiler cho việc này!

mã tùy chỉnh của tôi nhanh hơn 2 giây và sử dụng ít hơn 0,4 MB

Mặc dù tôi không nghi ngờ rằng thay đổi của bạn sẽ cải thiện hiệu suất, nhưng sẽ rất hữu ích khi cung cấp kết quả "trước" để so sánh các cải tiến.

Có lý do tại sao nhóm nòng cốt Magento không sử dụng walk('delete')thay vì tải sản phẩm trong một vòng lặp (mà tất cả chúng ta đều biết là một thực tiễn rất xấu)?

Vâng, chúng tôi biết từ các câu hỏi khác trên diễn đàn này như sau:

  • Cơ sở mã hóa Magento đã phát triển và phát triển qua nhiều năm
  • Nó đã có rất nhiều nhà phát triển làm việc trên nó
  • Các quy trình xử lý phát triển lõi Magento đã được cải thiện đáng kể qua thời gian họ làm việc trên nền tảng, bắt kịp các thực tiễn và kỹ thuật tốt nhất hiện đại đến mức Magento 2 hiện đang thể hiện nhiều thực tiễn thiết kế ứng dụng hiện đại hàng đầu

Vì vậy, tôi sẽ đề xuất rằng ví dụ bạn tìm thấy có lẽ là một trong những viên ngọc tiềm ẩn trong mã được viết cách đây rất lâu và / hoặc bởi một nhà phát triển ít kinh nghiệm hơn. Giống như nhiều mã lõi (và mã cộng đồng!) Nó sẽ được kiểm tra trên một tập dữ liệu nhỏ và không được kiểm tra trận chiến, do đó hiệu suất có thể không được giám sát chặt chẽ.

Là cải tiến của bạn có lợi, và phù hợp chặt chẽ hơn với thực tiễn tốt nhất so với mã ban đầu? Đúng. Tuy nhiên, bạn là nhà phát triển Magento [1.x] cộng đồng không có khả năng đóng góp các cải tiến được đề xuất mặc dù giống như bạn làm với Magento 2, vì vậy đề xuất của tôi sẽ là triển khai điều này trong một mô-đun cục bộ nếu bạn yêu cầu nó cho hiệu suất trong một trong các cửa hàng của bạn hoặc bỏ qua nó nếu nó không ảnh hưởng đến bạn nhưng bạn đã nhận thấy nó trong khi thực hiện một số nghiên cứu.

Là một bản cập nhật cho chỉnh sửa câu hỏi của bạn, tôi chắc chắn rằng bạn biết rằng phương pháp đi bộ trong Varien_Data_Collection chấp nhận một cuộc gọi lại tùy ý, vì vậy bạn sẽ được sử dụng nó cho bất cứ điều gì bạn muốn. Để gửi sự kiện trong ví dụ ban đầu, bạn có thể làm điều đó với chức năng đi bộ, cũng như xóa.

Lý do duy nhất tôi có thể tưởng tượng rằng việc tải sản phẩm trước khi xóa nó sẽ được sử dụng có thể là do các nhà quan sát gắn liền với sự kiện đó có thể cần một bộ dữ liệu đầy đủ không có sẵn mà không tải sản phẩm trước. Nếu đó là trường hợp, nó sẽ giải thích lý do tại sao họ sử dụng một singleton chứ không phải là một mô hình để ít nhất giảm thiểu các chi phí đối tượng.


Cảm ơn tôi đã thêm kết quả trước và sau vào bài viết. Vì vậy, bạn nghĩ rằng không có lý do cụ thể ngoài thực tế đó là mã cũ?
Raphael tại Nghệ thuật piano kỹ thuật số

2
Đó sẽ là dự đoán của tôi, yeah. Tải sản phẩm trước khi xóa sản phẩm sẽ không mang lại lợi ích gì ngoài việc kích hoạt các sự kiện tải, không liên quan đến việc xóa. Thông thường, bạn tải một sản phẩm để có được bộ dữ liệu đầy đủ của nó, có thể được yêu cầu cho một trong những người quan sát được đính kèm với sự kiện - nếu đó là trường hợp nó sẽ giải thích lý do tại sao họ sử dụng một mẫu đơn thay vì mô hình.
Robbie Averill

1
Xem bản chỉnh sửa của tôi với nhiều bài kiểm tra hơn, kết quả thậm chí còn điên rồ hơn
Raphael tại Digital Pianism

0

Tôi nghĩ rằng họ đang làm điều đó để kích hoạt catalog_controller_product_deletesự kiện đang được Mage_Tag sử dụng.

catalog_product_delete_beforehoặc catalog_product_delete_aftercó nghĩa là điều này là không cần thiết mặc dù tôi sẽ nghĩ. Tự hỏi nếu sự kiện cụ thể này cũng được sử dụng để ghi nhật ký hành động của Quản trị viên.


Nghĩ về điều đó cũng vậy nhưng đó chắc chắn không phải là lý do vì nó cũng xảy ra cho massDelete()hành động củaCustomerController.php
Raphael tại Digital Pianism

Xem bản chỉnh sửa của tôi với nhiều bài kiểm tra hơn, kết quả thậm chí còn điên rồ hơn
Raphael tại Digital Pianism

0

Tôi nghĩ rằng xóa hàng loạt sẽ hoạt động như xóa một sản phẩm (được nạp đầy đủ).

Đối với $collection->delete()câu trả lời đã được đưa ra. Nếu bạn không kích hoạt deleter_before, delete_aftertôi có thể phá vỡ một số tiện ích mở rộng và sẽ bỏ qua một số trình quan sát được sử dụng trong lõi.

$collection->walk('delete')có thể sẽ hoạt động, nhưng vẫn có nhược điểm là dữ liệu sản phẩm không đầy đủ. Điều này cũng có thể phá vỡ các nhà quan sát tùy chỉnh nếu họ dựa vào dữ liệu bổ sung, ví dụ như đối tượng mục chứng khoán.

Tôi đoán, nếu bạn thay đổi ->addAttributeToSelect('entity_id')để ->addAttributeToSelect('*')và thêm ->setFlag('require_stock_items', true)(để thêm dữ liệu chứng khoán để sản phẩm) nó sẽ không thực hiện tốt hơn sau đó "loop-delete".

Trông giống như phong cách xấu, nhưng tôi nghĩ rằng nó phù hợp cho cả hai hành động xóa hàng loạt.

Tôi sử dụng walk()delete()cho các mô hình tùy chỉnh quá, nhưng tôi biết rằng không có người quan sát hoặc entity_idlà đủ. Chỉ cần đề cập, walk()sẽ hoạt động với tất cả các sự kiện được sử dụng trong cốt lõi, vì chúng chỉ sử dụng $product->getId(), nhưng bạn không biết về các nhà quan sát bên thứ 3.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.