Как оптимизировать запрос к БД

Понимаю, что вопрос может быть достаточно странным, но может кто-нибудь может мне посоветовать, как ускорить выполнение следующего запроса, который выводит более 1000-3000 строк?

$select = 'newEraM.id AS id_m, newEraM.name AS m_name, newEraOrg.id AS id_org, newEraDtForecast.id AS id_forecast, newEraDtForecast.expense AS forecast_expense, newEraOrg.name AS org_name, newEraWorks.id AS id_work, newEraWorks.name AS work_name, newEraObj.id AS id_obj, newEraObj.name AS obj_name, newEraDtObj.id AS id_dt_obj, newEraDtObj.name AS dt_obj_name, newEraObj.id_obj_types, newEraObjTypes.id AS id_obj_type, newEraObjTypes.name AS obj_type_name, newEraDtData.id AS id_dt_data, newEraObj.id_m, newEraDtObj.id_obj, newEraDtData.id_obj, newEraDtData.date AS date, newEraDtData.fact_income AS fact_income, newEraDtData.fact_expense AS fact_expense, newEraDtData.fact_inner_income AS fact_inner_income, newEraDtData.fact_inner_expense AS fact_inner_expense, newEraDtData.fact_residue AS fact_residue';

$c = $modx->newQuery('newEraDtData');

$c->select($select);
$c->innerJoin('newEraDtObj', 'newEraDtObj'); // arguments are: className, alias
$c->leftJoin('newEraDtForecast', 'newEraDtForecast', '(newEraDtObj.id = newEraDtForecast.id_obj) and (newEraDtForecast.date_from <= newEraDtData.date and newEraDtForecast.date_to >= newEraDtData.date)');
$c->innerJoin('newEraOrg', 'newEraOrg', 'newEraDtObj.id_org = newEraOrg.id');
$c->innerJoin('newEraWorks', 'newEraWorks', 'newEraDtObj.id_work = newEraWorks.id');
$c->innerJoin('newEraObj', 'newEraObj', 'newEraDtObj.id_obj = newEraObj.id');
$c->innerJoin('newEraObjTypes', 'newEraObjTypes', 'newEraObj.id_obj_types = newEraObjTypes.id');
$c->innerJoin('newEraM', 'newEraM', 'newEraObj.id_m = newEraM.id');
if ($_POST['show_org']) {
    $c->where(array(
        'newEraOrg.id:IN' => $_POST['show_org'],
    ));
}
if ($_POST['show_obj']) {
    $c->where(array(
        'newEraObj.id:IN' => $_POST['show_obj'],
    ));
}
if ($_POST['from']) {
    $c->where(array(
        'newEraDtData.date:>=' => $_POST['from'],
    ));
}
if ($_POST['to']) {
    $c->where(array(
        'newEraDtData.date:<=' => $_POST['to'],
    ));
}

$c->sortby('newEraM.id', 'ASC');
$c->sortby('newEraObj.id', 'ASC');
$c->sortby('newEraDtObj.id', 'ASC');
$c->sortby('newEraDtData.date', 'ASC');

$objects = $modx->getIterator('newEraDtData', $c);
$count_objects = $modx->getCount('newEraDtData', $c);
GrinRom
01 марта 2015, 11:16
modx.pro
2 267
0

Комментарии: 15

Григорий Коленько
01 марта 2015, 16:58
0
Немного не по теме, но любопытно, а сколько сейчас это времени выполняется?
    GrinRom
    01 марта 2015, 17:50
    0
    Порядка 7-9 секунд
      GrinRom
      01 марта 2015, 17:52
      0
      2000 строк выводит, но проблема в том, что надо подрубить еще один запрос к другой таблице, правда поменьше.
    Іван Клімчук
    01 марта 2015, 17:02
    +1
    $c->prepare();
    echo $c->toSQL();
    и затем в phpmyadmin или просто в консоли mysql выполнить команду
    explain запрос
    и посмотреть, где он тупит.

    Дока по explain dev.mysql.com/doc/refman/5.0/en/explain.html
      GrinRom
      01 марта 2015, 17:54
      0
      Я получил следующее:
      1	SIMPLE	newEraDtObj	ALL	PRIMARY,id_obj	NULL	NULL	NULL	93	"Using temporary; Using filesort"
      1	SIMPLE	newEraOrg	eq_ref	PRIMARY	PRIMARY	4	srv22833_robur.newEraDtObj.id_org	1	"Using where"
      1	SIMPLE	newEraWorks	eq_ref	PRIMARY	PRIMARY	4	srv22833_robur.newEraDtObj.id_work	1	"Using where"
      1	SIMPLE	newEraDtData	ref	id_obj	id_obj	5	srv22833_robur.newEraDtObj.id	23	"Using where"
      1	SIMPLE	newEraDtForecast	ref	id_obj	id_obj	4	srv22833_robur.newEraDtObj.id	3	
      1	SIMPLE	newEraObj	eq_ref	PRIMARY	PRIMARY	4	srv22833_robur.newEraDtObj.id_obj	1	"Using where"
      1	SIMPLE	newEraM	eq_ref	PRIMARY	PRIMARY	4	srv22833_robur.newEraObj.id_m	1	"Using where"
      1	SIMPLE	newEraObjTypes	eq_ref	PRIMARY	PRIMARY	4	srv22833_robur.newEraObj.id_obj_types	1	"Using where"
      Но не очень понимаю куда смотреть((
        Іван Клімчук
        01 марта 2015, 17:59
        0
        Маловато информации он как-то выдал dev.mysql.com/doc/refman/5.0/en/explain-extended.html есть еще расширенный вызов. Вообще нужно смотреть, какие запросы и подзапросы вызывались, какие индексы использовались и тд. Анализировать данные и думать, как оптимизировать. Возможно где-то стоит разбить запрос на несколько, иногда несмотря на 2 запроса это работает быстрее. Куда именно смотреть я не скажу, это не тот случай, когда можно указать пальцем и сказать вот тут лажа.
          GrinRom
          01 марта 2015, 18:10
          0
          Я одно понять немогу, почему он делает запрос
          1	SIMPLE	newEraDtData	ref	id_obj	id_obj	5	srv22833_robur.newEraDtObj.id	23	101.91	"Using where"
          Ведь запрос идет изначально
          FROM `modx_new_era_dt_data` AS `newEraDtData`
            GrinRom
            01 марта 2015, 18:12
            0
            И опять же почему
            1	SIMPLE	newEraDtObj	ALL	PRIMARY,id_obj	NULL	NULL	NULL	93	100.00	"Using temporary; Using filesort"
            Если там связь 1 к 1 и идет переборка именно newEraDtData. Зачем он все перебирает.

            Да и в принципе почему так долго, вроде же не так много строк перебирает. Может это еще от чего-то быть?
      GrinRom
      01 марта 2015, 18:20
      0
      Тут посмотрел по времени, вроде как 7 секунд уходит на:

      foreach ($objects as $object) {
          $object_data[$object->get('id_m')]['m_name'] = $object->get('m_name');
          $object_data[$object->get('id_m')][$object->get('id_obj')]['obj_name'] = $object->get('obj_name');
          $object_data[$object->get('id_m')][$object->get('id_obj')]['obj_type_name'] = $object->get('obj_type_name');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')]['org_name'] = $object->get('org_name');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')]['work_name'] = $object->get('work_name');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')]['dt_obj_name'] = $object->get('dt_obj_name');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['date'] = $object->get('date');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['fact_income'] = $object->get('fact_income');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['fact_expense'] = $object->get('fact_expense');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['fact_inner_income'] = $object->get('fact_inner_income');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['fact_inner_expense'] = $object->get('fact_inner_expense');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['fact_residue'] = $object->get('fact_residue');
          $object_data[$object->get('id_m')][$object->get('id_obj')][$object->get('id_dt_obj')][$object->get('id_dt_data')]['forecast_expense'] = (float) $object->get('forecast_expense');
          $disabled = "disabled";
          $i++;
      }
      Может я тут перемудрил что-то?
        GrinRom
        01 марта 2015, 18:27
        0
        Изменил на:
        foreach ($objects as $object) {
        	$id_obj = $object->get('id_obj');
        	$id_m = $object->get('id_m');
        	$id_dt_obj = $object->get('id_dt_obj');
        	$id_dt_data = $object->get('id_dt_data');
            $object_data[$id_m]['m_name'] = $object->get('m_name');
            $object_data[$id_m][$id_obj]['obj_name'] = $object->get('obj_name');
            $object_data[$id_m][$id_obj]['obj_type_name'] = $object->get('obj_type_name');
            $object_data[$id_m][$id_obj][$id_dt_obj]['org_name'] = $object->get('org_name');
            $object_data[$id_m][$id_obj][$id_dt_obj]['work_name'] = $object->get('work_name');
            $object_data[$id_m][$id_obj][$id_dt_obj]['dt_obj_name'] = $object->get('dt_obj_name');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['date'] = $object->get('date');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['fact_income'] = $object->get('fact_income');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['fact_expense'] = $object->get('fact_expense');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['fact_inner_income'] = $object->get('fact_inner_income');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['fact_inner_expense'] = $object->get('fact_inner_expense');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['fact_residue'] = $object->get('fact_residue');
            $object_data[$id_m][$id_obj][$id_dt_obj][$id_dt_data]['forecast_expense'] = (float) $object->get('forecast_expense');
            $disabled = "disabled";
            $i++;
        }
        Сократилось на 3 на секунды, но все равно 4 секунды фигарит((
        GrinRom
        01 марта 2015, 19:11
        0
        Проблема в том, что этот файл вызывается через AJAX и фильтруется в зависимости от установленных input'ов. Из за этого, при включении кеширования фильтры не работают. Может есть какая возможность «и рыбку сьесть и на пенек присесть» — и кеширование включить и чтобы фильтры работали?
          Василий Наумкин
          01 марта 2015, 21:17
          2
          0
          А есть вообще смысл использовать объекты xPDO?

          Гораздо проще и быстрее будет использовать:
          if ($c->prepare() && $c->stmt->execute()) {
          	while ($row = $c->stmt->fetch(PDO::FETCH_ASSOC)) {
          		print_r($row);die;
          	}
          }
            GrinRom
            01 марта 2015, 22:38
            0
            Спасибо, я почему-то об этом даже не подумал. Попробую завтра.
              GrinRom
              02 марта 2015, 13:33
              0
              ВАУ!!! До 0,4 секунды скорость снизилась))))) Теперь все летит)) Спасибо!!!
            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
            15