- Профілювання запитів до бази даних
- Профілювання PHP VirtueMart інструментом XHprof
- Оптимізація VirtueMart: підсумки
- Оптимізація VirtueMart: доопрацювання
Стояло завдання оптимізації VirtueMart. Гальмувала вітрина товарів. Спочатку підозра падала на базу даних.
Профілювання запитів до бази даних
профілювання перконой не виявило нічого кримінального:
# Overall: 38 total, 16 unique, 0 QPS, 0x concurrency ____________________ # Attribute total min max avg 95% stddev median # ============ ======= ===== == ======= ======= ======= ======= ======= # Exec time 405ms 10ms 11ms 11ms 11ms 364us 10ms # Lock time 0 0 0 0 0 0 0 # Rows sent 0 0 0 0 0 0 0 # Rows examine 0 0 0 0 0 0 0 # Query size 15.76k 39 738 424.82 719.66 255.28 487.09
Загальний обсяг всіх відповідей бази даних - 15.76k, мінімум 39 байт, максимум - 738, час виконання - 405 мілісекунд, мінімум - 10 мс, максимум - 11.
Дані отримані без використання кеша запитів, в них не потрапили «швидкі» запити, що виконуються менш 0,01 сек.
0,4 секунди на базу даних - це, звичайно, багато. Треба прагнути, щоб на всю сторінку витрачалося не більше 0,2 сек.
Самі запити досить швидкі, в оптимізації особливої необхідності немає. Вони беруть «кількістю».
У ситуації, коли на відкриття сторінки потрібно 3 секунди, гальма з базою даних в 0,4 сек - не вузьке місце. З «прогревом» кеша запитів цей час істотно зменшиться.
Інші показники в нормі. Ні занадто «довгих» запитів.
Профілювання PHP VirtueMart інструментом XHprof
Вище - результати профілювання VirtueMart 2.0.20b за допомогою XHprof . Зроблено профілювання сторінки вітрини товарів.
Час виконання - 1,1 сек, з включеним кешем запитів, як на діючому сайті.
Після вибірки продуктів за умовою getProductListing, в скрипті по кожному продукту йде подгрузка детальної інформації getProductSingle.
Це займає 50% часу (IWall), причому цей процес запускається для кожного продукту - разом 126 раз (Calls).
Кожен виклик методу getProductSingle робить п'ять запитів до БД (за кодом) => 630 запитів. На зображенні 1737 - загальна кількість на всю сторінку.
База даних з такою кількістю запитів VirtueMart справляється легко - всього 10% загального часу (mysqli_query). Спасибі кешу!
Правильно має бути зроблено так: один раз виходить вся інформація по обраним продуктам, потім вона розкидається. Так обходяться п'ятьма запитами.
Оптимізація VirtueMart: підсумки
VirtueMart гальмує за рахунок неправильної реалізації отримання списку товарів, якість цього коду залишає бажати кращого. Прискорення в роботі з базою даних нічого не принесе.
Три варіанти:
Оптимізація VirtueMart: доопрацювання
Від версії до версії може відрізнятися. Ось мій випадок:
administrator / components / com_virtuemart / models / product.php
public function getProduct ($ virtuemart_product_id = NULL, $ front = TRUE, $ withCalc = TRUE, $ onlyPublished = TRUE, $ quantity = 1, $ customfields = TRUE, $ virtuemart_shoppergroup_ids = 0) {if (true &&! empty ($ Virtuemart_product_id) && $ front && JFactory :: getConfig () -> get ( 'caching')> = 1) {if (! class_exists ( 'CurrencyDisplay')) {require (JPATH_VM_ADMINISTRATOR. DS. 'Helpers'. DS. 'Currencydisplay.php'); // else 503 error} if ($ virtuemart_shoppergroup_ids! = 0 and is_array ($ Virtuemart_shoppergroup_ids)) {$ virtuemart_shoppergroup_idsString = implode ( '', $ Virtuemart_shoppergroup_ids); } Else {$ virtuemart_shoppergroup_idsString = $ virtuemart_shoppergroup_ids; } $ WithRating = $ this -> withRating? TRUE: 0; $ ProductKey = $ virtuemart_product_id. '-'. $ Front. '-'. $ WithCalc. '-'. $ OnlyPublished. '-'. $ Quantity. '-'. $ Customfields. '-'. $ Virtuemart_shoppergroup_idsString. '-'. $ WithRating; $ Mycache = JFactory :: getCache ( 'com_virtuemart_speedup', ''); $ Mycache -> setLifeTime (86400); $ Cache_content = $ mycache -> get ($ productKey); if (! is_object ($ Cache_content)) {$ cache_content = $ this -> _getProduct ($ virtuemart_product_id, $ front, $ withCalc, $ onlyPublished, $ quantity, $ customfields, $ virtuemart_shoppergroup_ids); $ Mycache -> store ($ cache_content, $ productKey); } Return $ cache_content; } Else {return $ this -> _getProduct ($ virtuemart_product_id, $ front, $ withCalc, $ onlyPublished, $ quantity, $ customfields, $ virtuemart_shoppergroup_ids); }} Public function _getProduct ($ virtuemart_product_id = NULL, $ front = TRUE, $ withCalc = TRUE, $ onlyPublished = TRUE, $ quantity = 1, $ customfields = TRUE, $ virtuemart_shoppergroup_ids = 0) {// тут старий варіант функції _getProduct}