Как не положить БД MySQL, используя поиск по атрибутам в WebAsyst ShopScript
28 февраля 2013 в 17:47 в категории Статьи о php 2 комментарияДобрый день, уважаемые читатели моего блога!
Данная статья является продолжением истории с WA SS, начало которой вы можете прочитать тут: WebAsyst наплевать на владельцев ShopScript или как положить БД владельца интернет-магазина ShopScript.
По многочисленным просьбам на форуме WebAsyst’a я пишу эту запись. Ничего сложного или необычного в данной статье нет, но тем не менее, благодаря этому хаку вы можете избежать «уложения» вашей БД MySQL.
Итак, приступим. Открываем файл:
C:\WebServers\home\domain\www\published\SC\html\scripts\core_functions\product_functions.php
В данном файле находим функцию _prepareSearchExtraParameters.
Немного о функции: данная функция составляет запрос в базу данных на основании тех параметров которые ей переданы (атрибуты, категории и т.п.).
На 507 строке мы видим открытие цикла, который прогоняет все item’ы и на 517 мы видим что каждый раз в массив $sqls_joins добавляется новый LEFT JOIN, который собственно и грузит нашу базу. Для примера могу сказать, что при тесте на локальном сервере запрос, имеющий 1x LEFT JOIN занял 0,002 сек., в то время как 2xLEFT JOIN заняло 8,8 секунд. (возможна погрешность в данных, ибо пишу спустя неделю после теста :), могу сказать одно, что разница между временем была в 500 раз).
На каждом проходе нашего цикла присоединяется ОДНА И ТАКЖЕ ТАБЛИЦА с разным именем, которое просто инкрементируется!
LEFT JOIN SC_product_options_values PrdOptVal0 ON p.productID=PrdOptVal0.`productID` LEFT JOIN SC_product_options_set PrdOptSet0 ON p.productID=PrdOptSet0.`productID` LEFT JOIN SC_product_options_values PrdOptVal1 ON p.productID=PrdOptVal1.`productID` LEFT JOIN SC_product_options_set PrdOptSet1 ON p.productID=PrdOptSet1.`productID`
Это происходит на 519 строке:
$sqls_joins[] = ' LEFT JOIN ?#PRODUCT_OPTIONS_VALUES_TABLE PrdOptVal'.$cnt.' ON p.productID=PrdOptVal'.$cnt.'.productID LEFT JOIN ?#PRODUCTS_OPTIONS_SET_TABLE PrdOptSet'.$cnt.' ON p.productID=PrdOptSet'.$cnt.'.productID LEFT JOIN ?#PRODUCTS_OPTIONS_VALUES_VARIANTS_TABLE PrdOptValVar'.$cnt.' ON PrdOptSet'.$cnt.'.optionID=PrdOptValVar'.$cnt.'.optionID AND PrdOptSet'.$cnt.'.variantID=PrdOptValVar'.$cnt.'.variantID ';
На 543 строке:
$sqls_joins[] = ' LEFT JOIN ?#PRODUCT_OPTIONS_VALUES_TABLE PrdOptVal'.$cnt.' ON p.productID=PrdOptVal'.$cnt.'.`productID` LEFT JOIN ?#PRODUCTS_OPTIONS_SET_TABLE PrdOptSet'.$cnt.' ON p.productID=PrdOptSet'.$cnt.'.`productID` ';
Таким образом, если у нас указано куча атрибутов при поиске, то наша база ляжет и будет лежать.
Для того чтобы избежать такого казуса, я внес банальные и возможно, не совсем красивые, с точки зрения правил хорошего тона в программировании, изменения.
Необходимо просто убрать все упоминания о переменной $cnt и изменить строки 519 и 543 таким образом, чтобы не создавался, а перезаписывался элемент массива. Таким образом мы уберем лишние объединения таблиц в запросе.
Возможно, лучшим бы было решение выноса данной записи из цикла, но в силу того, что изначально не понятно для чего нужен данный «костыль», я ограничился незначительными изменениями.
Если у вас возникнут вопросы или предложения по улучшению данного мануала — пишите мне в комментарии/вопросы-ответы — буду рад ответить или принять к сведению ваши предложения!
Удачной оптимизации кода! 🙂
2 комментария
приветствую…
а как с Вами связаться можно? спасибо
при помощи формы обратной связи в разделе контактов