Подсчет: несколько запросов или один запрос с несколькими подзапросами? - PullRequest
0 голосов
/ 06 декабря 2011

Я хочу сделать сводный скрипт, например, сколько новых пользователей там сегодня, вчера, на этой неделе, на прошлой неделе, в этом месяце, в прошлом месяце и т. Д.

Я использую CodeIgniter, поэтому мне интересно, какой из них лучше? Использование нескольких вызовов на моделях, подобных этой:

$this->model->get_today_users();
$this->model->get_yesterday_users();
$this->model->get_this_week_users();
// so on

Каждая из приведенных выше функций возвращает только количество пользователей с определенным диапазоном дат (например, SELECT COUNT (*) WHERE join_date = NOW () для today_users и т. Д., Конечно, с использованием активной записи CI).

Или лучше иметь один-единственный запрос со всеми необходимыми подзапросами, например так:

function stats(){
$this->db->select('*');
$this->db->select('(SELECT COUNT(*) FROM users WHERE join_date=NOW()) as today');
$this->db->select('(SELECT COUNT(*) FROM users WHERE join_date=NOW()-INTERVAL 1 DAY) as yesterday');
$this->db->select('(SELECT COUNT(*) FROM users WHERE WEEK(join_date)=WEEK(NOW()) ) as this_week');
$this->db->select('(SELECT COUNT(*) FROM users WHERE WEEK(join_date)=WEEK(NOW())-1 ) as last_week');
$this->db->select('(SELECT COUNT(*) FROM users WHERE MONTH(join_date)=MONTH(NOW()) ) as this_month');
$this->db->select('(SELECT COUNT(*) FROM users WHERE MONTH(join_date)=MONTH(NOW())-1 ) as last_month');
$this->db->from('users');
$ret = $this->db->get();
}

, а затем вызывать, например, $ data ['stat'] = $ this-> model-> stats (); поэтому в представлениях я могу вызвать $ stat-> today, $ stat-> this_week и т. д.

Заранее спасибо за ответы.

ОБНОВЛЕНИЕ: Что, если я хочу создать функцию, которая получает дату? Допустим, я должен сделать цикл примерно так:

//for the sake of simplicity
foreach(day in a month as $r){
    $this->model->get_user_on_this_day($r);
}

Это означает, что в течение 30-дневного месяца он будет повторяться 30 раз! Есть ли лучший способ, чем это?

Ответы [ 5 ]

1 голос
/ 06 декабря 2011

Правильный ответ, вероятно, таков: это зависит. С точки зрения повторного использования кода и читабельности, первый вариант, вероятно, лучше. С другой стороны, второй вариант означает, что вы обращаетесь к базе данных только один, а не три раза. Так что последнее, вероятно, будет лучше с точки зрения производительности, поскольку это означает, что вы обращаетесь к базе данных только один раз, что означает только одно соединение, одну транзакцию и т. Д. При больших базах данных, медленных соединениях и т. Д. Это будет означать более быстрые результаты.

0 голосов
/ 06 декабря 2011

Вы должны использовать отдельные запросы и кэшировать результат на определенную дату, поэтому вам никогда не придется запрашивать его более одного раза.

Поскольку люди не могут присоединиться в прошлом, данные для данного запроса (другиечем текущий день) никогда не изменится.

0 голосов
/ 06 декабря 2011

Один из способов сделать это - использовать первую опцию с одним запросом - использовать команду инициализации.

$this->model->buildmodel();

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

0 голосов
/ 06 декабря 2011

ИМО, ни один из подходов не оптимизирован.
Лучше всего использовать наименьший запрос, поэтому вы должны выполнить запрос GROUP BY, как показано ниже:

select date_format(join_date, '%Y-%m-%d') as the_date, count(*) as total
from users
where join_date between $start AND $end   <-- the date range
group by the_date;

Как только у вас есть результат, который вы можете установить массив, используя дату в качестве ключа,
тогда вы можете далее группировать по дням, неделям, месяцам ... (все, что вы хотите)


Похоже, ОП не понимает, как это работает: -

Приведенный выше запрос выполняет однократный запрос и возвращает строки, подобные

2011-12-09, 20 users join
2011-12-08, 10 users join
2011-12-07, 51 users join
...

Все, что вам нужно сделать, это перебрать результаты (не активная запись)

$query = $this->db->query($sql, array($start, $end));
$rtn   = array();
$total = 0;
foreach ($query->result() as $row)
{
  $rtn[$row->the_date] = $row->total;
  $total += $row->total;
}

К концу цикла $ total = общее количество пользователей, зарегистрированных с $ start до $ end.

Более эффективен и оптимизирован, чем выполнение 30 (или 31) запросов в цикле месяца-дня.

0 голосов
/ 06 декабря 2011

Рассматривали ли вы создание представления своей пользовательской таблицы, используя второй вариант, который вы упомянули?Для вашего запроса будет только один план выполнения, и он будет обрабатываться только в случае изменения данных в основной таблице.И вам понадобится только один простой запрос, чтобы получить то, что вам нужно.

И если вам нужно будет добавить больше подсчетов, как вы упомянули, вы просто добавляете столбцы в представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...