Перейти до вмісту
Пошук в
  • Детальніше...
Шукати результати, які ...
Шукати результати в ...

Жуткие тормоза (100 категорий , 10 000 товаров)


KingCrimson

Recommended Posts

Построил магазин на основе оригинального opencart 1.5.1.3

магазин интегрирован в джумлу 1.7

после импорта каталога товаров (10 000 едениц товара + 100 - 200 категорий )

начались нереальные тормаоза

(выделены сервер 4xXeon 4гига оперативы )

---

в mysql slow log имею следующую картину :

______________________________________________________________________ 001 ___

Count : 8.96k (1.26%)

Time : 1650.390618 s total, 184.195 ms avg, 150.109 ms to 614.001 ms max (21.14%)

95% of Time : 1488.393502 s total, 174.858 ms avg, 150.109 ms to 314.669 ms max

Lock Time (s) : 618.555 ms total, 69 ╣s avg, 57 ╣s to 1.751 ms max (0.58%)

95% of Lock : 576.596 ms total, 68 ╣s avg, 57 ╣s to 81 ╣s max

Rows sent : 1 avg, 1 to 1 max (0.06%)

Rows examined : 32.15k avg, 32.07k to 33.31k max (8.99%)

Database : xxxxx_xxxxx

Users :

xxx_xxx@localhost : 100.00% (8960) of query, 25.09% (178223) of all users

Query abstract:

SET timestamp=N; SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p

.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to

_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = 'S' AND p.status = 'S' AND p.date_available

Query sample:

SET timestamp=1320119802;

SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.pr

oduct_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.p

roduct_id = p2c.product_id) WHERE pd.language_id = '2' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id =

'0' AND (p2c.category_id = '20');

----

может кто подскажет куда копать ?

(адрес сайта grosscomp ру/new_site/ )

Надіслати
Поділитися на інших сайтах


Построил магазин на основе оригинального opencart 1.5.1.3

магазин интегрирован в джумлу 1.7

после импорта каталога товаров (10 000 едениц товара + 100 - 200 категорий )

начались нереальные тормаоза

...

----

может кто подскажет куда копать ?

(адрес сайта grosscomp ру/new_site/ )

opencart 1.5.1.3 сырой, требует оптимизации как структуры БД так и на уровне кода.
Надіслати
Поділитися на інших сайтах

может кто подскажет куда копать ?

Все места требующие земляных работ описать сложно, а если точнее невозможно...

Правильнее логировать медленные запросы и разбираться с каждым тормозом персонально.

Что касается приведённого запроса - добавь индекс:

ALTER TABLE `oc_product_to_category` ADD INDEX (`category_id`);

opencart 1.5.1.3 сырой, требует оптимизации как структуры БД так и на уровне кода.

Зря ты делаеш акцент на opencart 1.5.1.3.

По твоей реплике многие решат что только opencart 1.5.1.3 требует оптимизации структуры БД и кода.

Чем отличаются другие версии? Да ни чем... каждая версия имеет свой набор граблей.

  • +1 1
Надіслати
Поділитися на інших сайтах

Зря ты делаеш акцент на opencart 1.5.1.3.

По твоей реплике многие решат что только opencart 1.5.1.3 требует оптимизации структуры БД и кода.

Чем отличаются другие версии? Да ни чем... каждая версия имеет свой набор граблей.

Ну это применительно к ocStore, в ocStore какая никакая оптимизация была сделана, по отношению к другим версиям opencart разницы нет.
Надіслати
Поділитися на інших сайтах

Индексы строил пару дней назад

стало еще хуже

сейчас все индексы удалил

проблема действительно видимо в рекурсии

(Count : 8.96k (1.26%)) - это при том что после добавления товаров на сайт было всего 4- 5 заходов

---

Этот запрос принадлежит функции getTotalProducts

opencart\catalog\model\catalog\product.php

public function getTotalProducts($data = array()) {
		$sql = "SELECT COUNT(DISTINCT p.product_id) AS total FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_description pd ON (p.product_id = pd.product_id) LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'";
		
		if (isset($data['filter_name'])) {
			if (isset($data['filter_description']) && $data['filter_description']) {
				$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%' OR p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%') OR LCASE(pd.description) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%')";
			} else {
				$sql .= " AND (LCASE(pd.name) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%' OR p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_name'], 'UTF-8')) . "%'))";
			}
		}
		
		if (isset($data['filter_tag']) && $data['filter_tag']) {
			$sql .= " AND p.product_id IN (SELECT pt.product_id FROM " . DB_PREFIX . "product_tag pt WHERE pt.language_id = '" . (int)$this->config->get('config_language_id') . "' AND LCASE(pt.tag) LIKE '%" . $this->db->escape(mb_strtolower($data['filter_tag'], 'UTF-8')) . "%')";
		}
									
		if (isset($data['filter_category_id']) && $data['filter_category_id']) {
			if (isset($data['filter_sub_category']) && $data['filter_sub_category']) {
				$implode_data = array();
				
				$this->load->model('catalog/category');
				
				$categories = $this->model_catalog_category->getCategoriesByParentId($data['filter_category_id']);
				
				foreach ($categories as $category_id) {
					$implode_data[] = "p2c.category_id = '" . (int)$category_id . "'";
				}
				
				$sql .= " AND p.product_id IN (SELECT p2c.product_id FROM " . DB_PREFIX . "product_to_category p2c WHERE " . implode(' OR ', $implode_data) . ")";			
			} else {
				$sql .= " AND p.product_id IN (SELECT p2c.product_id FROM " . DB_PREFIX . "product_to_category p2c WHERE p2c.category_id = '" . (int)$data['filter_category_id'] . "')";
			}
		}
		
		if (isset($data['filter_manufacturer_id'])) {
			$sql .= " AND p.manufacturer_id = '" . (int)$data['filter_manufacturer_id'] . "'";
		}
				
		$query = $this->db->query($sql);
		
		return $query->row['total'];
	}

вот только не пойму откуда эта функция 9 тысяч раз была вызвана ...

  • +1 1
Надіслати
Поділитися на інших сайтах


поправил строки 44 и 58 в

catalog/controller/module/category.php

заменил $product_total = $this->model_catalog_product->getTotalProducts($data); на $product_total=1;

после этого все стало буквально летать .

функция getTotalProducts имеет двойной foreach для категорий и подкатегорий что и делает эту жуткую рекурсию

однако теперь напротив каждой категории я лицезрею цифру (1)

как бы сохранить вывод колличества товара в категории при этом ускорить вывод страницы ?

  • +1 1
Надіслати
Поділитися на інших сайтах


Мне кажется что у тебя не OC 1.5.1.3.1

Приведённая тобой функция getTotalProducts() сформирует такой запрос

SELECT COUNT(DISTINCT p.product_id) AS total 
FROM oc_product p 
LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) 
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) 
WHERE pd.language_id = '2' 
AND p.status = '1' 
AND p.date_available <= NOW() 
AND p2s.store_id = '0' 
AND p.product_id IN (SELECT p2c.product_id FROM oc_product_to_category p2c WHERE p2c.category_id = '20');

Откуда у тебя в логах этот запрос

SELECT COUNT(DISTINCT p.product_id) AS total 
FROM oc_product p 
LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) 
LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) 
LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) 
WHERE pd.language_id = '2' 
AND p.status = '1' 
AND p.date_available <= NOW() 
AND p2s.store_id = '0' 
AND (p2c.category_id = '20');
Надіслати
Поділитися на інших сайтах

Построил магазин на основе оригинального opencart 1.5.1.3

магазин интегрирован в джумлу 1.7

Дело в джумле 1.7. Моё мнение ни чем не обоснованно и не подтверждено.
Надіслати
Поділитися на інших сайтах


заменил $product_total = $this->model_catalog_product->getTotalProducts($data); на $product_total=1;

после этого все стало буквально летать .

ага, заодно и только один товар выводить, да?

а по делу - 10тыс записей это ерунда. нужно оптимизировать код.

Надіслати
Поділитися на інших сайтах

freelancer

товары все выводятся . Вывод значения кол ва товара в категории можно выключить. В таком состоянии и миллион товаров не проблемма . Вопрос только в том как сохранить вывод кол-ва товаров категории

Надіслати
Поділитися на інших сайтах


Вопрос только в том как сохранить вывод кол-ва товаров категории

а) кешировать вывод дерева категорий и вообще запросы к базе не делать (кешировать при мзменениии дерева категорий и редактирвоании товаров в админке)

б) оптимизировать построение дерева категорий до одного запроса (мне кажется, одним вполне можно будет обойтись)

(б) проще. (а) - это так, по ходу дела в голову пришло. Там переделывать больше и не уверен, стоит ли оно того.

Надіслати
Поділитися на інших сайтах


б) оптимизировать построение дерева категорий до одного запроса (мне кажется, одним вполне можно будет обойтись)

Мне не кажется, я точно знаю что это делается одним запросом, но человек упорно не хочет признаваться какую версию использует... а в зависимости от версии есть небольшое отличие в реализации.

Но индекс о котором я писал всё равно нужен... посмотри на explain'ы

mysql> EXPLAIN SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '20';

+----+-------------+-------+--------+----------------+---------+---------+------- ----------------------+------+--------------------------+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+----+-------------+-------+--------+----------------+---------+---------+------- ----------------------+------+--------------------------+

| 1 | SIMPLE | p2s | index | PRIMARY | PRIMARY | 8 | NULL | 7512 | Using where; Using index |

| 1 | SIMPLE | p | eq_ref | PRIMARY,status | PRIMARY | 4 | ocsfru.p2s.product_id | 1 | Using where |

| 1 | SIMPLE | pd | eq_ref | PRIMARY | PRIMARY | 8 | ocsfru.p2s.product_id,const | 1 | Using where; Using index |

| 1 | SIMPLE | p2c | eq_ref | PRIMARY | PRIMARY | 8 | ocsfru.p.product_id,const | 1 | Using where; Using index |

+----+-------------+-------+--------+----------------+---------+---------+------- ----------------------+------+--------------------------+

4 rows in set (0.00 sec)

mysql> ALTER TABLE `oc_product_to_category` ADD INDEX (`category_id`);

Query OK, 10022 rows affected (0.14 sec)

Records: 10022 Duplicates: 0 Warnings: 0

mysql> EXPLAIN SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '20';

+----+-------------+-------+--------+---------------------+-------------+-------- -+-----------------------------+------+--------------------------+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+----+-------------+-------+--------+---------------------+-------------+-------- -+-----------------------------+------+--------------------------+

| 1 | SIMPLE | p2c | ref | PRIMARY,category_id | category_id | 4 | const | 4 | Using where |

| 1 | SIMPLE | p2s | eq_ref | PRIMARY | PRIMARY | 8 | ocsfru.p2c.product_id,const | 1 | Using where; Using index |

| 1 | SIMPLE | p | eq_ref | PRIMARY,status | PRIMARY | 4 | ocsfru.p2c.product_id | 1 | Using where |

| 1 | SIMPLE | pd | eq_ref | PRIMARY | PRIMARY | 8 | ocsfru.p2s.product_id,const | 1 | Using where; Using index |

+----+-------------+-------+--------+---------------------+-------------+-------- -+-----------------------------+------+--------------------------+

4 rows in set (0.00 sec)

Надіслати
Поділитися на інших сайтах

Но индекс о котором я писал всё равно нужен... посмотри на explain'ы

explain'ы это не показатель/ приведите время запросов, у вас то наберется 10к записей

Надіслати
Поділитися на інших сайтах

explain'ы это не показатель

Если explain'ы не показатель - то я испанский лётчик...

Держи время...

mysql> SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '20';

+-------+

| total |

+-------+

| 4 |

+-------+

1 row in set (0.27 sec)

mysql> SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '20';

+-------+

| total |

+-------+

| 4 |

+-------+

1 row in set (0.16 sec)

mysql> ALTER TABLE `oc_product_to_category` ADD INDEX (`category_id`);

Query OK, 10022 rows affected (0.14 sec)

Records: 10022 Duplicates: 0 Warnings: 0

mysql> SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '20';

+-------+

| total |

+-------+

| 4 |

+-------+

1 row in set (0.01 sec)

mysql> SELECT COUNT(DISTINCT p.product_id) AS total FROM oc_product p LEFT JOIN oc_product_description pd ON (p.product_id = pd.product_id) LEFT JOIN oc_product_to_store p2s ON (p.product_id = p2s.product_id) LEFT JOIN oc_product_to_category p2c ON (p.product_id = p2c.product_id) WHERE pd.language_id = '1' AND p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '0' AND p2c.category_id = '20';

+-------+

| total |

+-------+

| 4 |

+-------+

1 row in set (0.00 sec)

у вас то наберется 10к записей

А что не видно?

Query OK, 10022 rows affected (0.14 sec)

Records: 10022 Duplicates: 0 Warnings: 0

Надіслати
Поділитися на інших сайтах

ваши тесты выеденого яйца не стоят.. 0.27, 0.16 что из этого можно понять?

Вы просили время запросов

explain'ы это не показатель/ приведите время запросов, у вас то наберется 10к записей

я дал время запросов... как будет понимать эти данные человек для которого explain не показатель - меня не волнует.
Надіслати
Поділитися на інших сайтах

сразу видно, что вы не занимались оптимизацией запросов. разница в 0,09с - ничто.

explain (как впрочем и EXPLAIN EXTENDED) может помочь, но на него сильно полагаться не стоит.

я попросил вас показать время реальных запросов потому как у вас реальная база и много записей. уже понял что зря

Надіслати
Поділитися на інших сайтах

сразу видно, что вы не занимались оптимизацией запросов. разница в 0,09с - ничто.

explain (как впрочем и EXPLAIN EXTENDED) может помочь, но на него сильно полагаться не стоит.

я попросил вас показать время реальных запросов потому как у вас реальная база и много записей. уже понял что зря

Хватит хохмить...

Уже все поняли что Вы специалист по оптимизации запросов.

Надіслати
Поділитися на інших сайтах

версия опенкарта 1.5.1.3

интегрирован посредством joocart

для вывода категорий используется модуль поставляемый с джукартом -но впринципе он тупо выдергивает вывод родного модуля категорий опенкарта и подсовывает его джумле .

с тем же каталогом на 10 000 едениц товара установил OcStore последний (testx . pcf1 . ru)

работает он быстрее - но все же 5 секунд ожидания при заходе на главную - это недопустимо долго.

в общем очевидно что функция подсчета товара в категории - самая неправильная функция опенкарта ..

помоему и один проход для некоторых магазинов будет тяжеловат (допустим каталог насчитывает 100 000 едениц товара )

в идеале добавить бы дополнительное поле для категорий в БД - куда писалось бы количество товара. а инициация пересчета происходила бы вручную по нажатии соответствующего пункта в админке.

Надіслати
Поділитися на інших сайтах


Хотелось бы получить ответ на этот вопрос http://opencartforum...dpost__p__33491, но раз ты его игнорируеш буду считать что ты по ошибке привёл не ту функцию, а не запрос...

Попробуй такую модель категорий category.php

Надіслати
Поділитися на інших сайтах

сразу видно, что вы не занимались оптимизацией запросов. разница в 0,09с - ничто.

...

я попросил вас показать время реальных запросов потому как у вас реальная база и много записей. уже понял что зря

Продолжаю офигевать. Вам уже и так, и эдак показали роль индексов. Дали конкретные цифры, показывающие как минимум 30-кратное ускорение при подсчете кол-ва товаров в категории. И падение времени фактически до нуля. Ответили на ВСЕ заданные вопросы. И всё мало? И непрофессионально?

Ну да, непрофессионально. Но не с того боку, с которого Вам было бы приятно. И смешно. Уж простите.

Надіслати
Поділитися на інших сайтах


в общем очевидно что функция подсчета товара в категории - самая неправильная функция опенкарта ..

помоему и один проход для некоторых магазинов будет тяжеловат (допустим каталог насчитывает 100 000 едениц товара )

Вам показали правильную. И время около нуля или сотых долей секунды. И весь запрос, возвращающий ВСЁ дерево категорий с уже подсчитанными количествами товаров, будет выполняться сопоставимое время, а не в 100-200 раз дольше. Почему вам с freelancer-ом ответ до сих пор не виден или непонятен - не знаю. Цифры вполне наглядные, а запросы показывают, что именно делается и на каких количествах.
Надіслати
Поділитися на інших сайтах


индексы работают когда все ок с запросами

а в моем случае после построения индексов упал сервер

кстати интересное наблюдение - без индексов злосчастный запрос грузил 1 ядро а с индексом все 4

Yesvik - попробую вечером

Надіслати
Поділитися на інших сайтах


Створіть аккаунт або увійдіть для коментування

Ви повинні бути користувачем, щоб залишити коментар

Створити обліковий запис

Зареєструйтеся для отримання облікового запису. Це просто!

Зареєструвати аккаунт

Вхід

Уже зареєстровані? Увійдіть тут.

Вхід зараз
  • Зараз на сторінці   0 користувачів

    • Ні користувачів, які переглядиють цю сторінку

×
×
  • Створити...

Important Information

На нашому сайті використовуються файли cookie і відбувається обробка деяких персональних даних користувачів, щоб поліпшити користувальницький інтерфейс. Щоб дізнатися для чого і які персональні дані ми обробляємо перейдіть за посиланням . Якщо Ви натиснете «Я даю згоду», це означає, що Ви розумієте і приймаєте всі умови, зазначені в цьому Повідомленні про конфіденційність.