Похоже, что все существующие ответы предлагают сделать GROUP BY code
на всю таблицу. Когда это логически правильно, в действительности этот запрос будет проходить через всю (!) Таблицу (чтобы убедиться, используйте EXPLAIN
). В моем случае в таблице менее 500 тыс. Строк, и выполнение ...GROUP BY code
занимает 0,3 секунды, что абсолютно недопустимо.
Однако я могу использовать знание своих данных здесь (читается как «показывать последние комментарии к сообщениям»):
- Мне нужно выбрать только 20 лучших записей
- Количество записей с одинаковым кодом в последних X записях относительно невелико
- Общее количество записей >> количество доступных
code
s >> количество «лучших» записей, которые вы хотите получить
Экспериментируя с числами, я обнаружил, что всегда могу найти 20 различных code
, если выберу только последние 50 записей. И в этом случае работает следующий запрос (имея в виду комментарий @smdrager о высокой вероятности использования id
вместо datetime
)
SELECT id, code
FROM tablename
ORDER BY id DESC
LIMIT 50
Выбор только последних 50 записей очень быстр, потому что не нужно проверять всю таблицу. А остальное - выбрать топ-20 с различными code
из этих 50 записей.
Очевидно, что запросы для набора из 50 (100, 500) элементов значительно быстрее, чем для всей таблицы с сотнями тысяч записей.
Необработанный SQL "Постобработка"
SELECT MAX(id) as id, code FROM
(SELECT id, code
FROM tablename
ORDER BY id DESC
LIMIT 50) AS nested
GROUP BY code
ORDER BY id DESC
LIMIT 20
Это даст вам список действительно быстрых id
, и, если вы хотите выполнить дополнительные JOIN, поместите этот запрос как еще один вложенный запрос и выполните все соединения с ним.
Внутренняя сторона "Постобработка"
И после этого вам нужно обработать данные на вашем языке программирования, чтобы включить в окончательный набор только записи с различными code
.
Какой-то псевдокод Python:
records = select_simple_top_records(50)
added_codes = []
top_records = []
for record in records:
# If record for this code was already found before
# Note: this is not optimal, better to use structure allowing O(1) search and insert
if record['code'] in added_codes:
continue
# Save record
top_records.append(record)
added_codes.append(record['code'])
# If we found all top-20 required, finish
if len(top_records) >= 20:
break