2

分析しようとしているこのmysqlクエリがあります。これは非常に遅く、ここのビジターテーブルは約50Kエントリであり、このクエリは返されません。Explainステートメントを試したところ、インデックスが使用可能であるにもかかわらず、訪問者テーブルでインデックスが使用されていないことがわかりました。今、これは私が解決するのに助けが必要な素晴らしいパズルです。ヒントをいただければ幸いです。

クエリ:

select distinct
  visitor0_.ID as ID130_,      

  case when visitor0_1_.id is not null then 1 when
  visitor0_.ID is not null then 0
  end as clazz_

from Visitor visitor0_ 
left outer join Operator visitor0_1_ on visitor0_.ID=visitor0_1_.id
where (visitor0_.ID not in
    (select operator1_.id 
     from Operator operator1_ 
     inner join Visitor operator1_1_ on operator1_.id=operator1_1_.ID))
  and (exists 
    (select visitorpro2_.ID 
     from VisitorProfileField visitorpro2_, ProfileField profilefie3_ 
     where visitorpro2_.profileFieldID=profilefie3_.ID 
       and visitorpro2_.visitorID=visitor0_.ID 
       and profilefie3_.name='subscription86' 
       and visitorpro2_.numberVal=1 
       and visitorpro2_.stringVal='Manual'))

出力スクリーンショットの説明:http: //grab.by/grabs/9c3a629a25fc4e9ec0fa54355d4a092c.png

4

2 に答える 2

2

私があなたのクエリから推測したところ、以下は同じ結果を生成し、サブクエリがなく、パフォーマンスが大幅に向上するはずです。

select v.ID as ID130_, 0 as clazz_
from Visitor v
left outer join (VisitorProfileField vpf join ProfileField pf 
                   on vpf.profileFieldID = pf.ID)
  on v.ID = vpf.visitorID and pf.name='subscription86' 
    and vpf.numberVal=1 and vpf.stringVal='Manual'
left outer join Operator o on v.ID = o.ID
where o.ID IS NULL;

一部間違っていたら教えてください。あなたの述語は、のIDに一致するIDをNOT IN除外しているようです。つまり、サブクエリは両方のテーブルにあるすべての ID のリストを生成するため、条件は への外部結合と簡単なテスト where と同等です。 VisitorOperatorNOT INOperatoro.ID IS NULL

これは、select-list の式が無意味であることを意味します。条件が の行に一致しない行CASEのみに一致する場合は、確実に 0 になるためです。VisitorOperator

あなたの質問には何かがひどく混乱していると思います。

VisitorProfileFieldまた、およびProfileFieldテーブルで EAV アンチパターンを使用しているようです。これはあなたに多くの問題を引き起こすでしょう。

于 2010-01-13T02:01:59.387 に答える
1

あなたのクエリは... 大きいです。それがあなたにとって何を達成するのか説明できますか?各訪問者 ID と、オペレーターではないオペレーターであるかどうかに関係なく、特定のプロファイルが設定されているようです。それはあまり意味がないので、そこに何かが欠けているに違いありません。

あなたがやろうとしていることの私の理解に基づいて、これが私の試みです:

select distinct visitor.ID, IF(operator.id IS NOT NULL, 1, 0) AS clazz
from Visitor left outer join Operator on visitor.ID = operator.id
where not exists 
    (select 'x' from Operator OperatorTwo where OperatorTwo.id = visitor.ID)
and exists
    (select 'x' from VisitorProfileField, ProfileField
        where VisitorProfileField.profileFieldID = ProfileField.ID
        and VisitorProfileField.profileFieldID.visitorID = visitor.ID
        and VisitorProfileField.profileFieldID.numberVal = 1
        and VisitorProfileField.profileFieldID.stringVal = 'Manual'
        and ProfileField .name = 'subscription86')

「operator1_1_」という名前の結合テーブルは使用されていないようです。削除できるはずです。そのテーブルに訪問者のレコードがあることを確認するためだけに使用している場合は、結合の代わりに存在を使用します。私はそれを落としました。

not in を not exists に切り替えました。MySQL の最適化が容易になると思います。ケースの代わりに IF を使用したのは、ケースが 2 つしかなく、入力が短かったためです。どちらがMySQLでより高速/簡単かはわかりません。

私の経験では、MySQL のパフォーマンスは、サブクエリにサブクエリがあると低下します。それらの最適化をあきらめ、行ごとに実行を開始するようです。結果の一時テーブルを (テスト目的で) 使用した場合、クエリの実行速度が大幅に向上することは間違いありません。

編集:

ビルは私よりも先に進みましたが、私は十分に行きませんでした。私は Bill の質問が好きで、CASE ステートメントに関する彼の結論に同意します。

于 2010-01-13T01:51:26.950 に答える