Содержание
Оформление заказа в магазине на Битрикс
При оформлении заказа наблюдалась сильная задержка, особенно при количестве товаров в корзине более 50.
Поиск проблемы с помощью профилировщика xhprof
Максимальная найденная задержка - 700 сек. Для предотвращения ситуации прерывания скрипта выставлено max_execution_time
в 900 сек и отменено прерывание скрипта при потере соединения с клиентом ignore_user_abort(true);
.
Поиск медленных SQL запросов с помощью Percona
Percona выдала следующую картину профилирования медленных запросов:
# Rank Query ID Response time Calls R/Call V/M Item # ==== ================== ============= ===== ======= ===== ============== # 1 0x93CFB226660D35EA 50.0813 76.3% 1 50.0813 0.00 UPDATE b_sale_product?product b_sale_basket # 2 0xB40B7BB93898D8B5 11.3354 17.3% 1 11.3354 0.00 INSERT SELECT b_sale_product?product b_sale_basket b_sale_product?product # 3 0x5D460ECCCA8798B9 2.2000 3.4% 1 2.2000 0.00 SELECT b_iblock b_lang b_iblock_element # MISC 0xMISC 1.9989 3.0% 28 0.0714 0.0 <24 ITEMS>
Самый медленный запрос:
UPDATE b_sale_product2product p2p, b_sale_basket b, b_sale_basket b1 SET p2p.CNT = p2p.CNT + 1 WHERE b.ORDER_ID = b1.ORDER_ID AND b.ID <> b1.ID AND b.ORDER_ID = 36057 AND p2p.PRODUCT_ID = b.PRODUCT_ID AND p2p.PARENT_PRODUCT_ID = b1.PRODUCT_ID\G
Вначале был сделан индекс, что сократило время на тестовом наборе с 10 до 3 сек:
ALTER TABLE `b_sale_basket` ADD INDEX `idx_save_order` (`ORDER_ID`, `ID`, `PRODUCT_ID`); -- 10 сек => 3 сек
Анализ и варианты решения
Таблица b_sale_product2product
отвечает за функционал «с этим товаром также покупают», причем несмотря на периодическую чистку ее размер вырос до 4,5 млн записей!
Решение - отключить функционал «С этим товаром покупают», так как он не используется. Варианты:
- штатными средствами: Настройки продукта > Настройки модулей > Интернет-магазин > Настройки также продаваемых продуктов. Возможно, что снятие всех опций поможет
- исправить код - патч может слететь при обновлении (
return;
в началеaddProductsFromOrder
иdeleteOldProducts
) - сделать «черную дыру»
ALTER TABLE b_sale_product2product ENGINE = BLACKHOLE
- оригинальный способ - удалить событие
onSaleOrderAdd
Удалить событие Битрикса onSaleOrderAdd
из админки нельзя, но можно это сделать запросом:
DELETE FROM `b_module_to_module` WHERE `TO_CLASS` = '\\Bitrix\\Sale\\Product2ProductTable' AND `TO_METHOD` = 'onSaleOrderAdd';
В итоге среднее время сократилось с 96 до 0,6 сек.
В последствии выяснилось, что еще надо вырубить агент CSaleProduct::RefreshProductList();
: