Как оптимизировать запрос к БД
Понимаю, что вопрос может быть достаточно странным, но может кто-нибудь может мне посоветовать, как ускорить выполнение следующего запроса, который выводит более 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);
Комментарии: 15
Немного не по теме, но любопытно, а сколько сейчас это времени выполняется?
Порядка 7-9 секунд
2000 строк выводит, но проблема в том, что надо подрубить еще один запрос к другой таблице, правда поменьше.
$c->prepare();
echo $c->toSQL();
и затем в phpmyadmin или просто в консоли mysql выполнить команду explain запрос
и посмотреть, где он тупит.Дока по explain dev.mysql.com/doc/refman/5.0/en/explain.html
Я получил следующее:
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"
Но не очень понимаю куда смотреть((
Маловато информации он как-то выдал dev.mysql.com/doc/refman/5.0/en/explain-extended.html есть еще расширенный вызов. Вообще нужно смотреть, какие запросы и подзапросы вызывались, какие индексы использовались и тд. Анализировать данные и думать, как оптимизировать. Возможно где-то стоит разбить запрос на несколько, иногда несмотря на 2 запроса это работает быстрее. Куда именно смотреть я не скажу, это не тот случай, когда можно указать пальцем и сказать вот тут лажа.
Я одно понять немогу, почему он делает запрос
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`
И опять же почему
Да и в принципе почему так долго, вроде же не так много строк перебирает. Может это еще от чего-то быть?
1 SIMPLE newEraDtObj ALL PRIMARY,id_obj NULL NULL NULL 93 100.00 "Using temporary; Using filesort"
Если там связь 1 к 1 и идет переборка именно newEraDtData. Зачем он все перебирает.Да и в принципе почему так долго, вроде же не так много строк перебирает. Может это еще от чего-то быть?
Тут посмотрел по времени, вроде как 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++;
}
Может я тут перемудрил что-то?
Изменил на:
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 секунды фигарит((
Проблема в том, что этот файл вызывается через AJAX и фильтруется в зависимости от установленных input'ов. Из за этого, при включении кеширования фильтры не работают. Может есть какая возможность «и рыбку сьесть и на пенек присесть» — и кеширование включить и чтобы фильтры работали?
А есть вообще смысл использовать объекты xPDO?
Гораздо проще и быстрее будет использовать:
Гораздо проще и быстрее будет использовать:
if ($c->prepare() && $c->stmt->execute()) {
while ($row = $c->stmt->fetch(PDO::FETCH_ASSOC)) {
print_r($row);die;
}
}
Спасибо, я почему-то об этом даже не подумал. Попробую завтра.
ВАУ!!! До 0,4 секунды скорость снизилась))))) Теперь все летит)) Спасибо!!!
На здоровье!
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.