
function cron_hour_counts()
{
$subids = get_subids();// массив вида array('1','3','10',...)
array_push($subids, '');
$from = '2011-10-20';//last_updated_date('tb_hour_counts');
$to = '2011-10-20';//last_date();
$days = days_interval($from, $to);
$result_array = array();
foreach ($subids as $subid)
{
for ($i = 0; $i < $days; $i++)
{
$hour = '00:00';
for ($t = 0; $t <= 23; $t++)
{
if ($t == 0)
{
$chour = date('H:i', strtotime($hour . '+' . $t . 'hour'));
$phour = date('H:i', strtotime('23:59'));
$date = date('Y-m-d', strtotime($from . '+' . $i . 'day'));
$date_prev = date('Y-m-d', strtotime($date . '- 1 day'));
}
else
{
$chour = date('H:i', strtotime($hour . '+' . $t . 'hour'));
$phour = date('H:i', strtotime($chour . '-1 hour'));
$date = date('Y-m-d', strtotime($from . '+' . $i . 'day'));
$date_prev = $date;
}
$unique_id_query = mysql_query("SELECT (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE (`date` < '" . mysql_real_escape_string($date) . "') OR (`date` = '" . mysql_real_escape_string($date) . "' AND `time` <= '" . mysql_real_escape_string($chour) . "')" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : "") . ") - (SELECT COUNT(DISTINCT `id`,`subid`) FROM `tb_stats` WHERE (`date` < '" . mysql_real_escape_string($date_prev) . "') OR (`date` = '" . mysql_real_escape_string($date_prev) . "' AND `time` <= '" . mysql_real_escape_string($phour) . "')" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : "") . ") AS `unique_ids`");
$unique_id_result = mysql_fetch_assoc($unique_id_query);
$total_id_query = mysql_query("SELECT COUNT(DISTINCT `id`,`subid`) AS `total_ids` FROM `tb_stats` WHERE `date` = '" . mysql_real_escape_string($date) . "' AND `time` <= '" . mysql_real_escape_string($chour) . "'" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : ""));
$total_id_result = mysql_fetch_assoc($total_id_query);
$unique_ip_query = mysql_query("SELECT (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE (`date` < '" . mysql_real_escape_string($date) . "') OR (`date` = '" . mysql_real_escape_string($date) . "' AND `time` <= '" . mysql_real_escape_string($chour) . "')" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : "") . ") - (SELECT COUNT(DISTINCT `ip`,`subid`) FROM `tb_stats` WHERE `date` <= '" . mysql_real_escape_string($date_prev) . "' AND `time` <= '" . mysql_real_escape_string($phour) . "'" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : "") . ") AS `unique_ips`");
$unique_ip_result = mysql_fetch_assoc($unique_ip_query);
$total_ip_query = mysql_query("SELECT COUNT(DISTINCT `ip`,`subid`) AS `total_ips` FROM `tb_stats` WHERE `date` = '" . mysql_real_escape_string($date) . "' AND `time` <= '" . mysql_real_escape_string($chour) . "'" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : ""));
$total_ip_result = mysql_fetch_assoc($total_ip_query);
$global_query = mysql_query("SELECT COUNT(`id`) AS `global` FROM `tb_stats` WHERE `date` = '" . mysql_real_escape_string($date) . "' AND `time` <= '" . mysql_real_escape_string($chour) . "'" . (!empty($subid) && is_numeric($subid) ? " AND `subid` = '" . mysql_real_escape_string($subid) . "'" : ""));
$global_result = mysql_fetch_assoc($global_query);
$result = array();
$result['date'] = $date;
$result['hour'] = $chour;
$result['subid'] = $subid;
$result['unique_ids'] = $unique_id_result['unique_ids'];
$result['total_ids'] = $total_id_result['total_ids'];
$result['unique_ips'] = $unique_ip_result['unique_ips'];
$result['total_ips'] = $total_ip_result['total_ips'];
$result['global'] = $global_result['global'];
$result_array[] = $result;
}
}
}
//db insert
print_r($result_array);
}
unique_ids = количество уникальных значений id+subid (тех которые ранее в таблице не встречались) за каждый час где subid = ...
unique_ips = = количество уникальных значений ip+subid (тех которые ранее в таблице не встречались) за каждый час где subid = ...
total_ids = количество distinct значений id+subid за каждый час где subid = ...
total_ips = количество distinct значений ip+subid за каждый час где subid = ...
global = количество distinct значений id за каждый час где subid = ...
При необходимости будет вести подсчёт не только за 24 часа текущих суток, но и нескольких дней.
Если принять во внимание 20 subid и одни сутки то это занимает 40 минут :(
Спустя 40 минут, 44 секунды (24.11.2011 - 00:33) Placido написал(а):
На какие поля индексы ставили?
Спустя 22 минуты, 28 секунд Placido написал(а):
И, по-хорошему, неплохо было бы написать, что хотим выбрать из этой таблицы и при каких условиях.
Честно - этот код читать эпически неудобно. Если запрос(ы) SQL сложный(сложные), и его(их) нужно оптимизировать, пишите только SQL, без PHP.
Спустя 22 минуты, 28 секунд Placido написал(а):
И, по-хорошему, неплохо было бы написать, что хотим выбрать из этой таблицы и при каких условиях.
Честно - этот код читать эпически неудобно. Если запрос(ы) SQL сложный(сложные), и его(их) нужно оптимизировать, пишите только SQL, без PHP.
Спустя 55 минут, 16 секунд (24.11.2011 - 01:28) hookman написал(а):
Цитата (Placido @ 23.11.2011 - 21:33) |
На какие поля индексы ставили? |
subid,date,time
нужно посчитать четыре значения unqiue_ids, unique_ips, total_ids, total_ips, global
Как они считаются я написал.
Сначала идёт цикл foreach который проходит по каждому subid, в нём for (для дней, их может быть несколько), и ещё один for для часов.
Код по-моему читабелен. Может запостить запросы в чистом виде?
Спустя 17 минут, 51 секунда (24.11.2011 - 01:46) Placido написал(а):
Поставьте составной индекс на поля date, time, subid.
Выборка значительно ускорится.
Просьба отписаться о результатах.
Спустя 3 минуты, 24 секунды Placido написал(а):
Поставьте составной индекс и проверьте.
А запостить запросы в чистом виде - это именно то, что я советовал. Ответов будет на порядок больше.
CREATE INDEX `ix_all` ON `tb_stats` (`date`, `time`, `subid`);
Выборка значительно ускорится.
Просьба отписаться о результатах.
Спустя 3 минуты, 24 секунды Placido написал(а):
Поставьте составной индекс и проверьте.
А запостить запросы в чистом виде - это именно то, что я советовал. Ответов будет на порядок больше.
Спустя 3 минуты, 41 секунда (24.11.2011 - 01:49) hookman написал(а):
Цитата (Placido @ 23.11.2011 - 22:46) |
Поставьте составной индекс на поля date, time, subid. CREATE INDEX `ix_all` ON `tb_stats` (`date`, `time`, `subid`); Выборка значительно ускорится. Просьба отписаться о результатах. |
У меня уже стоит составной индекс на эти три поля, а не по отдельности... Забыл упомянуть :)
Спустя 2 минуты, 24 секунды (24.11.2011 - 01:52) Placido написал(а):
Поля в составном индексе должны идти именно в таком порядке - (`date`, `time`, `subid`).
Спустя 30 секунд (24.11.2011 - 01:52) hookman написал(а):
Вот это unique_ids. Unique_ips идентично, только вместо id - ip.
SELECT (SELECT COUNT(DISTINCT id,subid) FROM tb_stats
WHERE subid = '1' AND (date < '2011-10-20' OR date = '2011-10-20' AND time <= '02:00')) - (SELECT COUNT(DISTINCT id,subid) FROM tb_stats
WHERE subid = '1' AND (date < '2011-10-20' OR date = '2011-10-20' AND time <= '01:00')) AS unique_ids;
Спустя 9 минут, 42 секунды (24.11.2011 - 02:02) Placido написал(а):
Цитата (hookman @ 23.11.2011 - 22:52) |
Вот это unique_ids. Unique_ips идентично, только вместо id - ip.
|
В таком случае, составной индекс сделайте так:
CREATE INDEX `ix_all` ON `tb_stats` (`subid`, `date`, `time`).
И проверьте запрос с новым индексом.
Спустя 9 минут, 38 секунд (24.11.2011 - 02:12) hookman написал(а):
Цитата (Placido @ 23.11.2011 - 23:02) |
В таком случае, составной индекс сделайте так: CREATE INDEX `ix_all` ON `tb_stats` (`subid`, `date`, `time`). И проверьте запрос с новым индексом. |
У меня индекс именно в таком порядке subid,date,time
Спустя 13 часов, 22 минуты, 48 секунд (24.11.2011 - 15:34) Placido написал(а):
Кстати, а почему бы из трех select-ов не сделать один? Глядишь, и скорость увеличится)))
SELECT COUNT(DISTINCT id,subid) AS unique_ids FROM tb_stats
WHERE subid = '1' AND (date < '2011-10-20' OR date = '2011-10-20' AND time BETWEEN '01:00' and '02:00');
Спустя 12 минут, 17 секунд (24.11.2011 - 15:47) hookman написал(а):
Цитата (Placido @ 24.11.2011 - 12:34) |
Кстати, а почему бы из трех select-ов не сделать один? Глядишь, и скорость увеличится)))SELECT COUNT(DISTINCT id,subid) AS unique_ids FROM tb_stats |
Этот запрос показывает количество уникальных значений за период с самой ранней даты до 2011-10-20 00:00 + с 2011-10-20 01:00 до 2011-10-20.
Мне же нужно количество значений(с 2011-10-20 01:00 до 2011-10-20 02:00) которые встречаются в таблице впервые
Спустя 49 минут, 19 секунд (24.11.2011 - 16:36) Placido написал(а):
SELECT COUNT(DISTINCT `id`) AS `unique_ids`
FROM `tb_stats`
WHERE `date` = '2011-10-20' AND `time` BETWEEN '01:00' AND '02:00'
AND `subid` = '1' AND `id` NOT IN (SELECT `id`
FROM `tb_stats`
WHERE `subid` = '1' AND `date` < '2011-10-20');
Спустя 4 часа, 34 минуты, 42 секунды (24.11.2011 - 21:11) hookman написал(а):
Цитата (Placido @ 24.11.2011 - 13:36) |
SELECT COUNT(DISTINCT `id`) AS `unique_ids` |
Если к этому добавить DISTINCT `id`,`subid` то какой синтаксис будет в NOT IN?
Сомневаюсь что этот запрос будет работать быстрее, но попробовать стоит. Спасибо.
Спустя 25 минут, 11 секунд (24.11.2011 - 21:36) Placido написал(а):
А смысл выбирать `subid`? Количество строк ведь будет то же самое, что и при выборке только `id` (`subid` у вас для всех выбранных записей будет равен 1, так как у вас есть условие WHERE `subid` = '1). А в NOT IN синтаксис тот, какой привел я.
Спустя 46 минут, 11 секунд (24.11.2011 - 22:22) hookman написал(а):
Цитата (Placido @ 24.11.2011 - 18:36) |
А смысл выбирать `subid`? Количество строк ведь будет то же самое, что и при выборке только `id` (`subid` у вас для всех выбранных записей будет равен 1, так как у вас есть условие WHERE `subid` = '1). А в NOT IN синтаксис тот, какой привел я. |
Не всегда $subid будет в условии WHERE, именно поэтому в запросе(смотреть скрипт) присутствует тернарный оператор.
Спустя 2 часа, 9 минут, 7 секунд (25.11.2011 - 00:31) hookman написал(а):
Этот запрос выполняется 1,2 сек:
А этот 0,06 сек:
SELECT COUNT(DISTINCT `id`,`subid`) AS `unique_ids`
FROM `tb_stats`
WHERE `date` = '2011-10-20'
AND `subid` = '5' AND CONCAT(`id`,0x3a,`subid`) NOT IN (SELECT CONCAT(`id`,0x3a,`subid`)
FROM `tb_stats`
WHERE `subid` = '5' AND `date` < '2011-10-20');
А этот 0,06 сек:
SELECT (SELECT COUNT(DISTINCT id,subid) FROM tb_stats
WHERE subid = '5' AND date <= '2011-10-20') - (SELECT COUNT(DISTINCT id,subid) FROM tb_stats
WHERE subid = '5' AND date < '2011-10-20') AS unique_ids;
Спустя 23 минуты, 51 секунда (25.11.2011 - 00:55) Placido написал(а):
Во-первых, уберите CONCATы. Зачем искать CONCAT(`id`,0x3a,`subid`), если подзапрос вернет CONCAT(`id`,0x3a,`subid`), где `subid`гарантированно будет равен 5 (у вас же и в запросе, и в подзапросе условие стоит WHERE `subid` = '5', значит CONCAT(0x3a,`subid`) всегда будет давать "0x3a5"). И у вас в первом запросе индексы не используются. Создайте составной индекс CREATE INDEX `ix_2` ON `tb_stats` (`subid`, `date`, `id`) и перепишите запрос так (для использования индексов):
SELECT COUNT(DISTINCT `id`,`subid`) AS `unique_ids`
FROM `tb_stats`
WHERE `subid` = '5'
AND `date` = '2011-10-20'
AND `id` NOT IN (SELECT `id`
FROM `tb_stats`
WHERE `subid` = '5' AND `date` < '2011-10-20');
Спустя 54 минуты, 23 секунды (25.11.2011 - 01:49) hookman написал(а):
Цитата (Placido @ 24.11.2011 - 21:55) |
Во-первых, уберите CONCATы. Зачем искать CONCAT(`id`,0x3a,`subid`), если подзапрос вернет CONCAT(`id`,0x3a,`subid`), где `subid`гарантированно будет равен 5 (у вас же и в запросе, и в подзапросе условие стоит WHERE `subid` = '5', значит CONCAT(0x3a,`subid`) всегда будет давать "0x3a5"). И у вас в первом запросе индексы не используются. Создайте составной индекс CREATE INDEX `ix_2` ON `tb_stats` (`subid`, `date`, `id`) и перепишите запрос так (для использования индексов): SELECT COUNT(DISTINCT `id`,`subid`) AS `unique_ids` |
Сделал. 0,58 сек. Так что не вариант.
Спустя 1 минута, 18 секунд (25.11.2011 - 01:51) Placido написал(а):
С индексом?
Спустя 25 минут, 15 секунд (25.11.2011 - 02:16) hookman написал(а):
Да
Спустя 1 день, 19 часов, 25 минут, 3 секунды (26.11.2011 - 21:41) hookman написал(а):
Придумал решение. В результате производительность увеличилась в 20 раз.
function cron_hour_counts()
{
$subids = get_subids();
//array_push($subids, '');
$from = '2011-10-20';//last_updated_date('tb_hour_counts');
$to = '2011-10-20';//last_date();
$days = days_interval($from, $to);
$result_array = array();
for ($i = 0; $i < $days; $i++)
{
$hour = '00:00';
for ($t = 0; $t <= 23; $t++)
{
$date = date('Y-m-d', strtotime($from . '+' . $i . 'day'));
$currentHour = date('H:i', strtotime($hour . '+' . $t . 'hour'));
$nextHour = date('H:i', strtotime($currentHour . '+59 minutes'));
$unique_ids_query = mysql_query("
SELECT COUNT(id) AS unique_ids,subid
FROM
(
SELECT id,subid,date,time
FROM tb_stats
WHERE date <= '" . mysql_real_escape_string($date) . "'
GROUP BY id,subid
) AS id_inner
WHERE date = '" . mysql_real_escape_string($date) . "'
AND time BETWEEN '" . mysql_real_escape_string($currentHour) . "' AND '" . mysql_real_escape_string($nextHour) . "'
GROUP BY subid;
");
pull_data('unique_ids', $date, $currentHour, $unique_ids_query, $subids, $result_array);
$unique_ips_query = mysql_query("
SELECT COUNT(ip) AS unique_ips,subid
FROM
(
SELECT ip,subid,date,time
FROM tb_stats
WHERE date <= '" . mysql_real_escape_string($date) . "'
GROUP BY ip,subid
) AS ip_inner
WHERE date = '" . mysql_real_escape_string($date) . "'
AND time BETWEEN '" . mysql_real_escape_string($currentHour) . "' AND '" . mysql_real_escape_string($nextHour) . "'
GROUP BY subid;
");
pull_data('unique_ips', $date, $currentHour, $unique_ips_query, $subids, $result_array);
$total_ids_query = mysql_query("
SELECT COUNT(DISTINCT id,subid) AS total_ids,subid
FROM tb_stats
WHERE date = '" . mysql_real_escape_string($date) . "'
AND `time` <= '" . mysql_real_escape_string($nextHour) . "'
GROUP BY subid
");
pull_data('total_ids', $date, $currentHour, $total_ids_query, $subids, $result_array);
$total_ips_query = mysql_query("
SELECT COUNT(DISTINCT ip,subid) AS total_ips,subid
FROM tb_stats
WHERE date = '" . mysql_real_escape_string($date) . "'
AND `time` <= '" . mysql_real_escape_string($nextHour) . "'
GROUP BY subid;
");
pull_data('total_ips', $date, $currentHour, $total_ips_query, $subids, $result_array);
$global_query = mysql_query("
SELECT COUNT(id) AS global,subid
FROM tb_stats
WHERE date = '" . mysql_real_escape_string($date) . "'
AND time <= '" . mysql_real_escape_string($nextHour) . "'
GROUP BY subid;
");
pull_data('global', $date, $currentHour, $global_query, $subids, $result_array);
}
}
print_r($result_array);
}