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

Тормоза в админке на странице заказов. Около 30 000 заказов.


Recommended Posts

Всем привет.

 

Тормозит страница заказов, а именно фильтрация. За фильтрацию отвечает функция GgetOrders($data = array()) модели sale/order.

public function getOrders($data = array()) {
	$sql = "SELECT o.order_id, CONCAT(o.firstname, ' ', o.lastname) AS customer, (SELECT os.name FROM " . DB_PREFIX . "order_status os WHERE os.order_status_id = o.order_status_id AND os.language_id = '" . (int)$this->config->get('config_language_id') . "') AS status, o.total, o.currency_code, o.currency_value, o.date_added, o.date_modified FROM `" . DB_PREFIX . "order` o";

	if (isset($data['filter_order_status_id']) && !is_null($data['filter_order_status_id'])) {
		$sql .= " WHERE o.order_status_id = '" . (int)$data['filter_order_status_id'] . "'";
	} else {
		$sql .= " WHERE o.order_status_id > '0'";
	}

	if (!empty($data['filter_order_id'])) {
		$sql .= " AND o.order_id = '" . (int)$data['filter_order_id'] . "'";
	}

	if (!empty($data['filter_customer'])) {
		$sql .= " AND CONCAT(o.firstname, ' ', o.lastname) LIKE '%" . $this->db->escape($data['filter_customer']) . "%'";
	}

	if (!empty($data['filter_date_added'])) {
		$sql .= " AND DATE(o.date_added) = DATE('" . $this->db->escape($data['filter_date_added']) . "')";
	}
	
	if (!empty($data['filter_date_modified'])) {
		$sql .= " AND DATE(o.date_modified) = DATE('" . $this->db->escape($data['filter_date_modified']) . "')";
	}
	
	if (!empty($data['filter_total'])) {
		$sql .= " AND o.total = '" . (float)$data['filter_total'] . "'";
	}

	$sort_data = array(
		'o.order_id',
		'customer',
		'status',
		'o.date_added',
		'o.date_modified',
		'o.total'
	);

	if (isset($data['sort']) && in_array($data['sort'], $sort_data)) {
		$sql .= " ORDER BY " . $data['sort'];
	} else {
		$sql .= " ORDER BY o.order_id";
	}

	if (isset($data['order']) && ($data['order'] == 'DESC')) {
		$sql .= " DESC";
	} else {
		$sql .= " ASC";
	}

	if (isset($data['start']) || isset($data['limit'])) {
		if ($data['start'] < 0) {
			$data['start'] = 0;
		}

		if ($data['limit'] < 1) {
			$data['limit'] = 20;
		}

		$sql .= " LIMIT " . (int)$data['start'] . "," . (int)$data['limit'];
	}

	$query = $this->db->query($sql);

	return $query->rows;
} 

 

 

Прошу помощи у тех, кто уже встречался с таким, кто ее оптимизировал. Есть второй выход - удалить часть заказов, но это исключено. 

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

какие вижу варианты пока не получил explain

1. проверить скорость если убрать подзапрос

(SELECT os.name FROM " . DB_PREFIX . "order_status os WHERE os.order_status_id = o.order_status_id AND os.language_id = '" . (int)$this->config->get('config_language_id') . "') AS status

2. проверить есть ли ключи на полях из where, из sort order.

выборка из одной таблицы не должна тормозить

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

Ответ прост

 

LIKE '%" . $this->db->escape($data['filter_customer']) . "%'"

 

 

При % в "начале" LIKE - идет перебор всей базы

 

Это очень тормозной запрос и ни какие индексы не помогут

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

Да там подзапрос при большой выборке еще может добавить "30`000" запросов к базе  :)

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

Ответ прост

 

 

При % в "начале" LIKE - идет перебор всей базы

 

Это очень тормозной запрос и ни какие индексы не помогут

а как же FULLTEXT индекс ? 

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

Да там подзапрос при большой выборке еще может добавить "30`000" запросов к базе  :)

если дело в подзапросе, то проблема легко решается его заменой на JOIN.

без expalin'а мы можем только гадать )

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

я имел ввиду замена like на MATCH (col1,col2,...) AGAINST (expr [search_modifier])

А, ну да, если все менять так и подзапрос на JOIN и на  MATCH поменять LIKE %

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

Сам запрос

SELECT o.order_id, CONCAT( o.lastname, ' ', o.firstname ) AS customer, o.order_status_id, o.webme_sent_review_reminder, (SELECT os.name FROM order_status os WHERE os.order_status_id = o.order_status_id AND os.language_id = '1') AS status, o.total, o.currency_code, o.currency_value, o.date_added, o.date_modified FROM `order` o WHERE o.order_status_id = '24' ORDER BY o.order_id DESC LIMIT 0,50

Выполняется за 1.4 секунды с включенным профайлером, что вполне приемлемо. Вот что выдал профайлер: Total time 13.7506 seconds | Total queries:563

 

Проблема была в vqmod/ocmod модулях для показа реферала (soforp_order_referer) и цвета заказа, они добавляют подзапросы:

SELECT referrer FROM `order_referrer` WHERE order_id = '29622' and cookie_name='last_referrer'

и

SELECT color FROM order_status_color WHERE order_status_id = '24'

Каждый из этих запросов выполняется в среднем за 0.15 сек. Авторам данных дополнений уже отписался. Кстати, отключили soforp_order_referer и заработало шустрей (1.5 сек). 

 

Решение

 

Проблема решилась без отключения модуля soforp_order_referer, путем добавления индексов  в таблицу order_referrer

 

order_referrer_id  int(11) AI

order_id                int(11) NULL  

cookie_name        varchar(100) NULL  

cookie_val            int(11) NULL  

referrer                 text NULL

 

Добавил индексы в поля по которым идет выборка:

ALTER TABLE `order_referrer`
ADD INDEX `order_id` (`order_id`);

ALTER TABLE `order_referrer`
ADD INDEX `cookie_name` (`cookie_name`);

С отключенным профайлером загрузка страницы встала на место и теперь занимает всего ~0.6 секунд. Всем спасибо за потраченное время. Спасибо, кстати, не знал про замену LIKE.

Змінено користувачем halfhope
Надіслати
Поділитися на інших сайтах

знал про замену LIKE.

 

 

Тоже аккуратно у MATCH свои подводные камни есть

Так что панацеи нет для "поиска" по тексту полноценного

 

Один вариант лучше на одних задачах, другой на других

 

Универсального решения - НЕТ :(

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

Тоже аккуратно у MATCH свои подводные камни есть

Так что панацеи нет для "поиска" по тексту полноценного

 

Один вариант лучше на одних задачах, другой на других

 

Универсального решения - НЕТ :(

всё верно.

MATCH (col1,col2,...) AGAINST (expr [search_modifier]) это не замена LIKE, это функция, которая, возможно, при каких-то условиях будет работать быстрее чем LIKE

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

Проблема решилась без отключения модуля soforp_order_referer, путем добавления индексов  в таблицу order_referrer

 

пробуйте заменить подзапросы на LEFT JOIN, возможно еще скорости добавится

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

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

а разве нельзя сделать проверку на наличие индекса и если нет, добавлять автоматом?

 

PS: сам еще не сталкивался с проверкой по наличию индексов - если что не так, сапогами прошу не кидать :ugeek:

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

а разве нельзя сделать проверку на наличие индекса и если нет, добавлять автоматом?

 

PS: сам еще не сталкивался с проверкой по наличию индексов - если что не так, сапогами прошу не кидать :ugeek:

Alex там не только проверка на индексы- там проблема в запросе - очень большая выборка получается - более 500 подзапросов :(

Там сам запрос надо менять перехватив модель и обработать через __call

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

Там сам запрос надо менять перехватив модель и обработать через __call

- дяденька.. я не настоящий сварщик! (с) :-D

 

сорри за офтоп

просто стало интересно - зачем выносить мозг пользователям ручным выполнением запроса в БД, если можно добавить автоматом?

или нельзя?

 

ну-ка пойду тестить! :ugeek:

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

AlexDW
    private $fields = array(
        'product_attribute' => array('product_id'),
        'product_option_value' => array('option_value_id', 'product_id'),
        'product_to_category' => array('category_id'));

...

    public function check_indexes() {
        foreach($this->fields as $table => $indexes) {
            $query = $this->db->query("SHOW INDEX FROM `" . DB_PREFIX . $table . "`");

            $keys = array();
            foreach($query->rows as $row) {
                    $keys[] = $row['Column_name'];
            }
            $keys = array_diff($indexes, $keys);
            foreach($keys as $key) {
                $this->db->query("ALTER TABLE `" . DB_PREFIX . $table . "` ADD INDEX ( `" . $key . "` )");
            }
        }
    }
  • +1 1
Надіслати
Поділитися на інших сайтах

работает, тестил так:

    $sql = "SHOW INDEX FROM " . DB_PREFIX ."product WHERE KEY_NAME = 'productz'";
    $query = $this->db->query($sql);
    if ($query->num_rows == 0) {
        $this->db->query("ALTER TABLE " . DB_PREFIX ."product ADD INDEX `productz` (`product_id`,`cost`)");
    }

freelancer - спасибо за решение!

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

работает, тестил так:

    $sql = "SHOW INDEX FROM " . DB_PREFIX ."product WHERE KEY_NAME = 'productz'";
    $query = $this->db->query($sql);
    if ($query->num_rows == 0) {
        $this->db->query("ALTER TABLE " . DB_PREFIX ."product ADD INDEX `productz` (`product_id`,`cost`)");
    }

freelancer - спасибо за решение!

 

 

Можно так еще

        $r = $this->db->query("SHOW KEYS FROM `" . DB_PREFIX . "review_fields` WHERE Key_name ='review_id'");
        if ($r->num_rows == 0) {
            $msql = "ALTER TABLE `" . DB_PREFIX . "review_fields`  ADD INDEX (`review_id`)";
            $query = $this->db->query($msql);
        }
Надіслати
Поділитися на інших сайтах

  • 7 months later...

 

Можно так еще

        $r = $this->db->query("SHOW KEYS FROM `" . DB_PREFIX . "review_fields` WHERE Key_name ='review_id'");
        if ($r->num_rows == 0) {
            $msql = "ALTER TABLE `" . DB_PREFIX . "review_fields`  ADD INDEX (`review_id`)";
            $query = $this->db->query($msql);
        }

А где надо делать это?

Тоже самое у меня, проблема .... много товара ()15-20к) и групп под 150-200 ... И как быть? что бы шустрее работало?

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

kolomenec, это не код магической кнопки "сделать все зашибись"

почитайте тему с самого начала, возможно поймете что обсуждалось

 

в вашем случае - ищите по форуму по темам ускорение opencart

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

А где надо делать это?

Тоже самое у меня, проблема .... много товара ()15-20к) и групп под 150-200 ... И как быть? что бы шустрее работало?

 

Для начала попробуйте добавить индексы в БД, проверить будет ли так же тормозить. Если да, то обратитесь к пользователю @snastik, у него backend оптимизация хорошо получается и куча модулей для этого есть.

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

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

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

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

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

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

Вхід

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

Вхід зараз

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

Important Information

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