• Как выбрать одним запросом 5 последних записей каждой категории в MySQL?

    kozlice
    @kozlice
    Пробуем. Все замеры на таблице с 5000 записей, рандомным cid от 1 до 10, id primary, на cid индекс.

    На PostgreSQL можно запрашивать
    SELECT a.*
    FROM somedata AS a
    WHERE a.id IN (
    	SELECT b.id
    	FROM somedata AS b
    	WHERE b.cid = a.cid
    	ORDER BY b.id DESC
    	LIMIT 5
    )
    ORDER BY a.cid DESC, a.id DESC

    Но запрос медленный (0.125 сек), и время выполнения растёт прямо пропорционально кол-ву записей и категорий. MySQL вообще не поддерживает LIMIT во вложенных запросах, идём дальше. Мастерим страшного монстра:
    SELECT a.*
    FROM somedata AS a
    WHERE a.id IN (
    	SELECT id
    	FROM somedata AS b
    	WHERE b.cid = a.cid AND (SELECT COUNT(*) FROM somedata AS c WHERE c.id >= b.id AND c.cid = b.cid) <= 5
    )
    ORDER BY a.cid DESC, a.id DESC

    Он, конечно, справился, получены верные данные, но выполнение такого запроса заняло… 15.87 сек. Не хотеть, правда? :)

    Самым производительным оказалось эстетически уродливое уродливое решение. Склеиваем в PHP запросы для каждой категории в единый с помощью UNION:
    (SELECT * FROM somedata WHERE cid = 1 ORDER BY id DESC LIMIT 5)
    UNION
    (SELECT * FROM somedata WHERE cid = 2 ORDER BY id DESC LIMIT 5)
    UNION
    (SELECT * FROM somedata WHERE cid = 3 ORDER BY id DESC LIMIT 5)

    и т.д. до cid = 10, и о чудо: запрос выполняется на MySQL за 0.002 сек, выдавая нужный результат.

    Хотя, возможно я упустил какое-то очевидное решение с приемлемой производительностью. Если найдёте – расскажите нам :)
    Ответ написан
    3 комментария