Подзапрос медленный - PullRequest
3 голосов
/ 09 мая 2019

У меня есть таблица MySQL с 10 миллионами строк.Для каждой строки у меня есть столбец id и столбец date.Столбец id не является уникальным, и для одного id имеется несколько строк с разными значениями для date, обычно 3-6 дат для каждого id.Я хочу выбрать строки с самыми последними date для их id.

Мой запрос:

SELECT   id,
         date
FROM     tab a
WHERE    a.date = (SELECT MAX(date)
                   FROM   tab b
                   WHERE  a.id=b.id)

выполняется очень медленно и занимает несколько минут.Такое чувство, что это можно сделать намного быстрее.Каковы лучшие практики здесь?

Ответы [ 4 ]

5 голосов
/ 09 мая 2019

Почему не просто?

SELECT   id,
         MAX(date) date
FROM     tab
GROUP BY id;
1 голос
/ 09 мая 2019

Я предполагаю, что есть еще столбцы, которые вы хотите получить из таблицы (в противном случае решение DanB - лучший путь).

Давайте разделим это на два шага:

  1. Получите максимальные даты для каждого id
  2. Получите необходимые данные

Первый шаг очень прост:

SELECT id, max(date)
FROM tab
GROUP BY id

Важно: оба столбца должны быть проиндексированы.

Теперь второй шаг - сложная часть.Как получить все необходимые данные?

Что бы я сделал:

  • Создать временную таблицу с результатом запроса выше,
  • Индексэто, и
  • Присоединитесь к таблице с этой новой временной таблицей.

Итак, давайте попробуем:

CREATE TEMPORARY TABLE temp_dates
     SELECT id, max(date) as mdate
     FROM tab
     GROUP BY id;

ALTER TABLE temp_dates
     ADD UNIQUE INDEX u_id (id),
     ADD INDEX i_mdate (mdate);

SELECT a.id, a.date -- Add all the columns you need
FROM tab AS a
     INNER JOIN temp_dates AS b ON a.id=b.id and a.date=b.mdate;

Надеюсь, это поможет.

0 голосов
/ 09 мая 2019

Ваш запрос может быть самым быстрым способом подойти к этому. Но вам определенно нужен индекс на tab(id, date) для производительности. Оба столбца в индексе.

Если у вас есть другая таблица идентификаторов, то следующий способ часто является самым быстрым:

select ids.id,
       (select max(t.date)
        from tab t
        where t.id = ids.id
       ) as max_date;

Для этого требуется тот же индекс, но не требуется сканирование полной таблицы (а также индекса).

0 голосов
/ 09 мая 2019

Прежде всего: id должен быть уникальным. Это их цель.

Теперь моя рекомендация:

select
  id,
  max(date) as latest_date
from a

join b
  on b.id = a.id

group by a.id

order by latest_date;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...