2009-05-26 3 views
1

У меня есть таблица, которая подсчитывает вхождения одного конкретного действия разных пользователей на различных объектах:MySQL: запросить верхний п агрегирование

CREATE TABLE `Actions` (
    `object_id` int(10) unsigned NOT NULL, 
    `user_id` int(10) unsigned NOT NULL, 
    `actionTime` datetime 
); 

Каждый раз, когда пользователь выполняет это действие, строка вставляется. Я могу сосчитать, сколько действия были выполнены на каждом объекте, а также объекты порядка по «деятельности»:

SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
ORDER BY action_count; 

Как я могу ограничить результаты лучших российских объектов? Предложение LIMIT применяется до агрегации, что приводит к неправильным результатам. Таблица потенциально огромна (миллионы строк), и мне, вероятно, нужно посчитать десятки раз в минуту, поэтому я хотел бы сделать это как можно эффективнее.

Редактировать: На самом деле, машина права, и я ошибся со временем, когда применяется LIMIT. Мой запрос вернул правильные результаты, но графический интерфейс, представляющий их мне, отбросил меня ... этот вопрос делает этот вопрос бессмысленным. Сожалею!

ответ

2

на самом деле ... LIMIT применяется последним, после окончательного предложения HAVING. Поэтому он не должен давать неверные результаты. Однако, поскольку LIMIT применяется последним, он не будет выполнять более быстрое выполнение вашего запроса, так как временную таблицу нужно будет создать и отсортировать в порядке количества действий до измельчения результата. Также не забудьте отсортировать в порядке убывания:

SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
ORDER BY action_count DESC 
LIMIT 10; 

Вы можете попробовать добавить index в object_id для оптимизации. Таким образом, нужно будет сканировать только индекс, а не таблицу Действия.

0
SELECT * FROM (SELECT object_id, count(object_id) AS action_count 
     FROM `Actions` 
     GROUP BY object_id 
     ORDER BY action_count) LIMIT 10; 
1

Как насчет:

SELECT * FROM 
(
SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
ORDER BY action_count 
) 
LIMIT 15 

Кроме того, если у вас есть какой-то степени, что должно быть минимальное количество действий, которые должны быть включены (например, верхние п те, безусловно, более 1000), вы может повысить эффективность путем добавления предложения HAVING:

SELECT * FROM 
(
SELECT object_id, count(object_id) AS action_count 
FROM `Actions` 
GROUP BY object_id 
HAVING action_count > 1000 
ORDER BY action_count 
) 
LIMIT 15 
1

Я знаю, что эта нить составляет 2 года, но stackflow по-прежнему считает это актуальным, поэтому здесь идет мой $ 0,02. Предложения ORDER BY являются вычислительно дорогостоящими, поэтому их следует избегать в больших таблицах. Трюк я использовал (частично из SQL Джо Селко для Smarties) что-то вроде:

SELECT COUNT(*) AS counter, t0.object_id FROM (SELECT COUNT(*), actions.object_id FROM actions GROUP BY id) AS t0, (SELECT COUNT(*), actions.object_id FROM actions GROUP BY id) AS t1 WHERE t0.object_id < t1.object_id GROUP BY object_id HAVING counter < 15 

Даст вам 15 лучших отредактированных объектов без сортировки. Обратите внимание, что с v5 mysql будет кэшировать только наборы результатов для точно повторяющихся запросов (whitespace incl), поэтому вложенный запрос не будет кэшироваться. Использование представления разрешит эту проблему.

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

Сторона примечания: запрос действительно удобен для средних функций без сортировки

Смежные вопросы