Экспресс-сравнение производительности MySQL и SQL Server

StackOverflow https://stackoverflow.com/questions/405795

Вопрос

У меня есть несколько сложный запрос примерно из 100 тысяч строк.

Запрос выполняется за 13 секунд в SQL Server Express (выполняется в моем окне разработки).

Выполнение одного и того же запроса с той же индексацией и таблицами в MySQL 5.1 занимает более 15 минут (выполняется в моем рабочем окне - гораздо более мощном и протестированном со 100% ресурсами) И иногда запрос приводит к сбою компьютера из-за ошибки нехватки памяти.

Что я делаю не так в MySQL?Почему это занимает так много времени?

select e8.*
from table_a e8
inner join (
    select max(e6.id) as id, e6.category, e6.entity, e6.service_date
    from (
        select e4.* 
        from table_a e4
        inner join (
            select max(e2.id) as id, e3.rank, e2.entity, e2.provider_id, e2.service_date
            from table_a e2
            inner join (
                select min(e1.rank) as rank, e1.entity, e1.provider_id, e1.service_date
                from table_a e1
                where e1.site_id is not null
                group by e1.entity, e1.provider_id, e1.service_date 
            ) as e3
            on e2.rank= e3.rank
            and e2.entity = e3.entity
            and e2.provider_id = e3.provider_id
            and e2.service_date = e3.service_date
            and e2.rank= e3.rank
            group by e2.entity, e2.provider_id, e2.service_date, e3.rank
        ) e5
        on e4.id = e5.id
        and e4.rank= e5.rank                            
    ) e6
    group by e6.category, e6.entity, e6.service_date 
) e7
on e8.id = e7.id and e7.category = e8.category
Это было полезно?

Решение

Этот ответ, который я первоначально пытался опубликовать на ваш удаленный вопрос, в котором не указывалось, что это была проблема с MySQL.Я бы все равно продолжил и использовал SQL Server для рефакторинга запроса с использованием CTE, а затем преобразовал обратно во вложенные запросы (если таковые остались).Извините за форматирование, Джефф Этвуд прислал мне оригинальный опубликованный текст, и мне пришлось переформатировать его снова.

Трудно обойтись без данных, ожидаемых результатов и хороших имен, но я бы преобразовал все вложенные запросы в CTE, объединил их, назвал осмысленно и провел рефакторинг, начав с исключения столбцов, которые вы не используете.Удаление столбцов не приведет к улучшению, потому что оптимизатор довольно умен, но это даст вам возможность улучшить ваш запрос - возможно, с учетом некоторых или всех CTE.Я не уверен, что делает ваш код, но вы можете счесть новые функции типа RANK() полезными, потому что, похоже, вы используете шаблон обратного поиска со всеми этими самосоединениями.

Так что вместо этого начните отсюда.Я просмотрел улучшения e7 для вас, неиспользуемые столбцы из e7 могут указывать либо на дефект, либо на неполное представление о возможностях группировки, но если эти столбцы действительно не нужны, то это может просочиться обратно через вашу логику в e6, e5 и e3.Если группировка в e7 правильная, то вы можете исключить все, кроме max (id), из результатов и объединения.Я не понимаю, почему у вас должно быть несколько MAX (id) для каждой категории, потому что это умножило бы ваши результаты при присоединении, поэтому MAX (id) должен быть уникальным внутри категории, и в этом случае категория является избыточной при объединении.

WITH e3 AS (
select min(e1.rank) as rank,
e1.entity,
e1.provider_id,
e1.service_date
from table_a e1
where e1.site_id is not null
group by e1.entity, e1.provider_id, e1.service_date
)

,e5 AS (
select max(e2.id) as id,
e3.rank,
e2.entity,
e2.provider_id,
e2.service_date
from table_a e2
inner join e3
on e2.rank= e3.rank
and e2.entity = e3.entity
and e2.provider_id = e3.provider_id
and e2.service_date = e3.service_date
and e2.rank= e3.rank
group by e2.entity, e2.provider_id, e2.service_date, e3.rank
)

,e6 AS (
select e4.* -- switch from * to only the columns you are actually using
from table_a e4
inner join e5
on e4.id = e5.id
and e4.rank= e5.rank
)

,e7 AS (
select max(e6.id) as id, e6.category -- unused, e6.entity, e6.service_date
from e6
group by e6.category, e6.entity, e6.service_date
-- This instead
-- select max(e6.id) as id
-- from e6
-- group by e6.category, e6.entity, e6.service_date
)

select e8.*
from table_a e8
inner join e7
on e8.id = e7.id
and e7.category = e8.category
-- THIS INSTEAD on e8.id = e7.id

Другие советы

100 000 строк не заняли бы 13 секунд, если бы были доступны эффективные индексы.Я подозреваю, что разница связана с тем фактом, что SQL server имеет гораздо более надежный оптимизатор запросов, чем MySQL.То, что есть в MySQL, больше похоже на синтаксический анализатор SQL, чем на Оптимизатор.

Вам нужно будет предоставить гораздо больше информации - полные схемы всех участвующих таблиц и полный список индексов для каждой, для начала.

Затем получите некоторое представление о том, что это за данные и для чего предназначен запрос.Что-то вроде Варианта использования.

Было бы интересно ОБЪЯСНИТЬ ПЛАН с обоими, чтобы увидеть, в чем заключались различия.Я не уверен, что это сравнение яблока и апельсина, но мне было бы любопытно.

Я не знаю, может ли это могу помочь, но это был первый поиск по запросу "mysql query optimizer".

Вот еще один это могло бы того стоить.

Единственная известная мне база данных с открытым исходным кодом, у которой есть CTE, - это Firebird (http://www.firebirdsql.org/rlsnotesh/rlsnotes210.html#rnfb210-cte)

Я думаю, что Postgres появится в версии 8.4

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top