MySQL подзапрос действительно медленный ... Обходной путь? - PullRequest
5 голосов
/ 14 мая 2011

Я протестировал следующий, казалось бы, простой запрос на MySQL 5.0, 5.1, 5.5 и обнаружил, что он очень медленный.

select * from entry where session_id in
    (select session_id from entry where created_at > [some timestamp])

У нескольких записей может быть один и тот же идентификатор сеанса, но разные временные метки made_at.Запрос предназначен для захвата всех записей, в которых есть хотя бы одна запись из того же идентификатора сеанса, чей созданный_кат больше указанной метки времени.

Я видел, как другие говорили о проблемах производительности подзапроса MySQL с аналогичными запросами, и чтоMySQL считает подзапрос зависимым запросом и выполняет полное сканирование таблицы внешнего запроса.Предлагаемые обходные пути были что-то вроде:

select * from entry where session_id in
    (select session_id from
        (select session_id from entry where created_at > [some timestamp])
    as temp)

Однако этот хак у меня не работает и делает его еще медленнее.

Есть идеи о том, как переписать этот запрос?

Ответы [ 3 ]

6 голосов
/ 14 мая 2011

В зависимости от вашего распределения данных, используйте это

SELECT  e.*
FROM    (
        SELECT  session_id, MAX(created_at)
        FROM    entry
        GROUP BY
                session_id
        HAVING  MAX(created_at) > $mytimestamp
        ) ed
JOIN    entry e
ON      e.session_id = ed.session_id

(создать индекс для (session_id, created_at)) или это:

SELECT  DISTINCT e.*
FROM    entry ed
JOIN    entry e
ON      e.session_id = ed.session_id
WHERE   ed.created_at > $mytimestamp

(создать два отдельных индекса для created_at и session_id)

3 голосов
/ 09 июня 2011

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

select * from entry where session_id in
    (select (select session_id from entry where created_at > [some timestamp]))

В моем случае исходный запрос мог работать часами, используя соединение или "обычный" трюк двойного подзапроса, с модифицированным двойным подзапросом это заняло 0 секунд:)

1 голос
/ 14 мая 2011

Как насчет:

SELECT DISTINCT e2.*
    FROM entry e1
        INNER JOIN entry e2
            ON e1.session_id = e2.session_id
    WHERE e1.created_at > [some timestamp]

Если у вас их еще нет, вероятно, вам также пригодятся индексы created_at и session_id.

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