1

約 100K 行のやや複雑なクエリがあります。

クエリは SQL Server Express で 13 秒で実行されます (開発ボックスで実行)

同じインデックスとテーブルを使用した同じクエリを 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
4

5 に答える 5

2

この回答は、MySQLに問題があることを示さなかった、削除された質問に最初に投稿しようとしました。それでも先に進み、SQL Serverを使用してCTEを使用してクエリをリファクタリングしてから、ネストされたクエリに変換し直します(残っている場合)。フォーマットについて申し訳ありませんが、Jeff Atwoodから投稿された元のテキストが送られてきたので、もう一度フォーマットし直さなければなりませんでした。

データ、期待される結果、適切な名前なしで行うのは難しいですが、ネストされたすべてのクエリを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
于 2009-01-02T14:01:18.903 に答える
1

効率的なインデックスが利用可能であれば、100,000 行に 13 秒もかからないはずです。この違いは、SQL サーバーが MySQL よりもはるかに強力なクエリ オプティマイザを備えているためだと思われます。MySQL が持っているものは、オプティマイザーよりも SQL パーサーに近いものです。

手始めに、参加するすべてのテーブルの完全なスキーマと、それぞれのインデックスの完全なリストなど、さらに多くの情報を提供する必要があります。

次に、データが何であるか、およびクエリが何を生成することを意図しているかについてのアイデア。ユースケースの順序で何か。

于 2009-01-02T01:22:57.273 に答える
1

違いが何であるかを見るために、両方で EXPLAIN PLAN を実行することは興味深いでしょう。リンゴとオレンジの比較かどうかはわかりませんが、興味があります。

これが役立つかどうかはわかりませんが、これは「mysql クエリ オプティマイザー」の検索で最初にヒットしたものです。

于 2009-01-02T02:14:19.247 に答える
0

ここに価値があるかもしれない別のものがあります。

于 2009-01-02T02:20:53.477 に答える