Сравнение производительности MySQL и SQL Server Express - PullRequest
1 голос
/ 02 января 2009

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

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

Один и тот же запрос с той же индексацией и таблицами занимает более 15 минут для запуска на MySQL 5.1 (выполняется на моем производственном компьютере - гораздо более мощный и протестирован с использованием 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

Ответы [ 5 ]

2 голосов
/ 02 января 2009

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

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

Так что начните отсюда. Я рассмотрел улучшения e7 для вас, столбцы, неиспользуемые из e7, могут указывать либо на дефект, либо на неполное представление о возможностях группировки, но если эти столбцы действительно не нужны, то это может просочиться через всю вашу логику в e6, е5 и е3. Если группировка в 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
1 голос
/ 02 января 2009

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

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

1 голос
/ 02 января 2009

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

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

Тогда какое-то представление о том, что представляют собой данные и для чего предназначен запрос. Что-то в порядке использования.

0 голосов
/ 15 апреля 2009

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

Postgres будет в 8,4 я думаю

0 голосов
/ 02 января 2009

Вот еще один , который может стоить.

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