PHP, МуSql - как объединить несколько запросов в один?

131
01 января 2020, 17:10

Есть несколько запросов, к базе данных. Суммарно по времени они выполняются более 10 секунд.

"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2015-12-01" AND reviews_data<="2015-12-31" AND reviews_author="user" AND login<>"user"", duration=1.4160809516907
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-01-01" AND reviews_data<="2016-01-31" AND reviews_author="user" AND login<>"user"", duration=1.4150810241699
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-02-01" AND reviews_data<="2016-02-31" AND reviews_author="user" AND login<>"user"", duration=1.2920739650726
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-03-01" AND reviews_data<="2016-03-31" AND reviews_author="user" AND login<>"user"", duration=1.6590950489044
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-04-01" AND reviews_data<="2016-04-31" AND reviews_author="user" AND login<>"user"", duration=1.6340939998627
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-05-01" AND reviews_data<="2016-05-31" AND reviews_author="user" AND login<>"user"", duration=1.5760898590088
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-06-01" AND reviews_data<="2016-06-31" AND reviews_author="user" AND login<>"user"", duration=1.6550948619843
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-07-01" AND reviews_data<="2016-07-31" AND reviews_author="user" AND login<>"user"", duration=1.556088924408
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-08-01" AND reviews_data<="2016-08-31" AND reviews_author="user" AND login<>"user"", duration=1.3690779209137
"SELECT COUNT(reviews_data) as cnt FROM tblkworkreviews WHERE reviews_data>="2016-09-01" AND reviews_data<="2016-09-31" AND reviews_author="user" AND login<>"user"", duration=1.4540841579437

Подскажите, как их объединить в один?

Answer 1

Можно сделать так:

  1. Выберите все строки для автора reviews_author="user" AND login<>"user" (заменив логины на id'шники и построив индексы, скорее всего сможете ускорить запрос).
  2. Используйте вторую часть условия для получения значения 1 или 0 и агрегатную функцию sum.

Чтобы решать такие задачки, надо представлять что у вас происходит в базе при запросе и как можно "срезать углы". В общем случае, при запросе база перебирает строки из таблицы и и сравнивает их значения с ограничениями where. Если есть подходящие индексы, количество строк, которые надо перебрать, база может сократить.

То есть получается, что каждый запрос у вас это цикл типа:

$cnt = 0;
foreach ($rows as $row) {
    if ($row == $where) {
        $cnt++;
    }
}

Чем больше строк надо перебрать, тем дольше выполняется такой цикл. В вашем случае, с некоторой долей вероятности (чтобы знать наверняка, воспользуйтесь утилитой explain), перебираются одни и те же наборы строк.

$cnt1 = 0;
foreach ($rows as $row) {
    if ($row == $where1) {
        $cnt1++;
    }
}
$cnt2 = 0;
foreach ($rows as $row) {
    if ($row == $where2) {
        $cnt2++;
    }
}
...

Если подумать, то это можно оптимизировать, посчитав всё в одном прогоне.

$cnt1 = 0;
$cnt2 = 0;
foreach ($rows as $row) {
    if ($row == $where1) {
        $cnt1++;
    }
    if ($row == $where2) {
        $cnt2++;
    }
}

В этом и заключается моё решение. Немного другой способ (но по сути идентичный) вам советуют в комментариях.

UPD для тех, кто в танке :-)

select
    sum(`reviews_data` >= "2015-12-01" and `reviews_data` <= "2015-12-31") as `cnt1`
    sum(`reviews_data` >= "2016-01-01" and `reviews_data` <= "2016-01-31") as `cnt2`
from `tblkworkreviews`
where
    `reviews_author` = "user"
    and `login` <> "user";
READ ALSO
Как в Yii2 добавить атрибут к модели?

Как в Yii2 добавить атрибут к модели?

У меня есть вот такой вот html код, в котором есть vue атрибуты

145
Как задать в Jquery атрибут name?

Как задать в Jquery атрибут name?

Как правильно назвать имя в Jquery, если в html прописан атрибут name из php массива? Просто DATA[name] js не понимает, и скрипт не срабатывает

141
Подсчет товаров в категориях рекурсия

Подсчет товаров в категориях рекурсия

Прошу помощи, сваял функцию, которая должна считать, а она считает только до первого предка, прошу помощи

120