MySQL, многократный GROUP BY

kruzer25

Хочется оптимизировать что-то типа
SELECT COUNT(*) FROM (SELECT `UserID`,`Hour` WHERE `Hour`>12 AND `Hour`<18 GROUP BY CONCAT(`UserID`,'_',`Hour`) FROM `MyTable`) GROUP BY `Hour`
Хотелось бы сделать что-то типа SELECT COUNT(`UserID`) FROM `MyTable` GROUP BY `Hour`,`UserID` - оно будет работать?
И вообще, как лучше тут сделать?
В refman практически ничего о GROUP BY нету...

kruzer25

Или в случае запроса
SELECT COUNT(*) FROM (SELECT `UserID`,`Hour` WHERE `Hour`>12 AND `Hour`<18 AND COUNT(*)>=2 GROUP BY CONCAT(`UserID`,'_',`Hour`) FROM `MyTable`) GROUP BY `Hour`

kruzer25

И ещё такой вопрос- есть таблица с PRIMARY KEY ID (он используется, т.е. удалять этот столбец нельзя и есть столбец, в котором записано время - оно монотонно не убывает при возрастании ID. Можно ли как-нибудь ускорить выборку по времени, не заводя при этом ещё один индекс для него?

bastii

SELECT COUNT(*) FROM (SELECT `UserID`,`Hour` WHERE `Hour`>12 AND `Hour`<18 GROUP BY CONCAT(`UserID`,'_',`Hour`) FROM `MyTable`) GROUP BY `Hour`
а зачем CONCAT? разве такой запрос не дает тоже самое?
SELECT COUNT(*) FROM (SELECT `UserID`,`Hour` FROM `MyTable` WHERE `Hour`>12 AND `Hour`<18 GROUP BY `UserID`,`Hour` ) GROUP BY `Hour`
и вообще странно, как-то, разве с твоим GROUP BY с CONCAT, MySql не ругается, на `UserID`,`Hour` в SELECT?
не знаю как в MySql, но в MsSql можно через COUNT(DISTINCT) сделать:
SELECT COUNT(DISTINCT 'UserID')
FROM 'MyTable'
WHERE 'Hour'>12 AND 'Hour'<18
GROUP BY 'hour'
хотя план такой же получается, сам запрос немного проще выглядит
наиболее эффективно такой запрос будет выполняться, когда есть индекс с ключом ('hour', 'UserID' хотя через индекс с ключом 'hour' тоже скорее всего довольно быстро получится

kruzer25

а зачем CONCAT? разве такой запрос не дает тоже самое?
Проблема в том, что я несмог найти описание GROUP BY, и не знал, как он работает с несколькими выражениями (если вообще работает).

bastii

можно в GROUP BY использовать несколько выражений, тогда в одну группу будут попадать все строки, где по каждому выражению из GROUP BY совпадают значения

kruzer25

SELECT COUNT(DISTINCT 'UserID')
FROM 'MyTable'
WHERE 'Hour'>12 AND 'Hour'<18
GROUP BY 'hour'
Спасибо, так, наверное, получится.
Записей на один и тот же Hour не так много - индекс на UserID ни к чему. Но сейчас там такая схема, как я уже описал - есть ещё столбец ID, и Hour возрастают с увеличением ID, ID - Primary key, а на Hour индекса нету... как можно сделать, не создавая ещё один лишний индекс, чтобы при этом побыстрее подобные запросы выполнялись? (потому что, при сортировке по ID, получается, что уже всё отстортировано по Hour).
А что можно сделать с твоим способом, если хочется поставить дополнительное условие с UserID - например, чтобы смотреть только на те UserID, на которые для данного Hour не меньше двух записей?

pitrik2

SELECT COUNT(DISTINCT ...
MySql это понимает

bastii

про то как сделать без индекса я не знаю

bastii

А что можно сделать с твоим способом, если хочется поставить дополнительное условие с UserID - например, чтобы смотреть только на те UserID, на которые для данного Hour не меньше двух записей?
SELECT COUNT(DISTINCT 'UserID')
FROM 'MyTable' t1
WHERE 'Hour'>12 AND 'Hour'<18 AND (SELECT Count(*) FROM 'MyTable' t2 WHERE t1.UserID = t2.UserID AND t1.'hour' = t2.'hour') >= 2
GROUP BY 'hour'
не знаю как хорошо этот запрос будет исполняться, ничего лучше не придумывается

kruzer25

Мда уж... у меня получилась вот такая хрень:
SELECT `Hour`,COUNT(*) FROM (SELECT `UserID`,`Hour` FROM (SELECT `UserID`,`Hour`,COUNT(*) as `RequestNum` FROM `MyTable` WHERE `Hour`>=123 AND `Hour`<456 GROUP BY `UserID`,`Hour`) as `sel2` WHERE `RequestNum`>=2) as `sel3` GROUP BY `Hour`

bastii

пользуйся HAVING:
SELECT COUNT(DISTINCT userid)
FROM (
SELECT hour, userid
FROM MyTable
WHERE Hour>12 AND Hour<18
GROUP BY hour, userid
HAVING count(*) >= 2
) t
GROUP BY hour
да, так пожалуй лучше, а то в предыдущем моем запросе джойн вылазит
Оставить комментарий
Имя или ник:
Комментарий: