by Romul То, что интересно мне

11Фев/100

SQL. Извращение над группировкой

Требуется получить последние темы для каждого рубрики форума. На ум сразу приходит запрос вида:

Вариант 1.

SELECT id AS rubric_id, (
SELECT id
FROM `forum_topic`
WHERE rubric_id = `forum_rubric`.id
ORDER BY updated DESC
LIMIT 1
) AS last_topic_id
FROM `forum_rubric` ;

Структуры таблиц.

CREATE TABLE `forum_rubric` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID рубрики форума',
`status_id` tinyint(3) unsigned NOT NULL COMMENT 'ID статуса',
`name` varchar(255) DEFAULT NULL COMMENT 'Название',
PRIMARY KEY (`id`)
) ;

CREATE TABLE `forum_topic` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID темы',
`status_id` tinyint(3) unsigned NOT NULL COMMENT 'ID статуса',
`rubric_id` int(10) unsigned NOT NULL COMMENT 'ID рубрики',
`title` varchar(255) NOT NULL COMMENT 'Заголовок',
`added` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Создан',
`updated` timestamp NULL COMMENT 'Обновлен',
PRIMARY KEY (`id`),
KEY `rubric_id` (`rubric_id`,`updated`),
) ;

А вот как можно извратиться и сделать одним запросом:

Вариант 2.

SELECT rubric_id, SUBSTRING_INDEX( GROUP_CONCAT( id ORDER BY updated DESC ) , ',', 1 ) AS last_topic_id
FROM `forum_topic`
GROUP BY rubric_id ;

1. группируем по рубрики
2. собираем ID в строку, сортируя в обратном порядке по дате
3. обрезаем до первой запятой

Результате на данных:
- 50 рубрик
- 100.000 тем

Вариант 1:
1.0464 сек, обход ~10.000 записий
Вариант 2:
0.0629 сек, обход всех 100.000 записей

Если в запросе участвует WHERE,
добавим к примеру status_id = 3

Вариант 3.

SELECT id AS rubric_id, (
SELECT id
FROM `forum_topic`
WHERE rubric_id = `forum_rubric`.id AND status_id = 3
ORDER BY updated DESC
LIMIT 1
) AS last_topic_id
FROM `bank_forum_rubric` ;

1.0136 сек, обход ~2.000 записей

если добавить ключ на rubric_id + status_id:
0.2013 сек, обход ~450 записей

Вариант 4.

SELECT rubric_id, SUBSTRING_INDEX( GROUP_CONCAT( id ORDER BY updated DESC ) , ',', 1 ) AS last_topic_id
FROM `forum_topic`
WHERE status_id = 3
GROUP BY rubric_id ;

0.2059 сек, обход ~20.000 записей

Итог.

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

Комментарии (0) Пинги (0)

Пока нет комментариев.


Leave a comment

(required)

 

Нет обратных ссылок на эту запись.