2016-11-28 37 views
0

私はかなり新しいMySQLです。次のクエリを使って、wordpressユーザー/ usermetaテーブルから値のリストを取得しています。パフォーマンスとは別にクエリが機能するのはひどいので、改善する方法がわかりません。最適化/ MySQLクエリ

クエリには12秒以上かかりますが、400人程度のユーザーであれば、これ以上追加すると大きな問題になります。

MySQLはユニークな列はないと報告していますが、ユーザーIDがすでに結果の一部であるため、これを修正する方法がわかりません。

これはデフォルトのクエリです。完全なクエリでは、郵便番号検索の距離を決定するために緯度/経度を使用して余分な計算が追加されますが、これには余分な時間がかかりません。

私が苦労した主な部分は、値が外部キーとして関連付けられたuser_idとともにmeta_keyおよびmeta_valueとして保存されるという事実です。

私は既に大きな違いをもたらした以下の提案の一部でクエリを更新しました。私はまだ誰かが私がそれらを聞くのが好きなアイデアを持っている場合は、ジョインなどの数を減らすことによってクエリ自体を改善することができると思う。

これは変更を含むクエリであり、距離による検索のための追加部分です。

SELECT DISTINCT 
    wp_users.ID, 
    wp_users.user_email, 
    city_latitude.meta_value as cityLat, 
    city_longitude.meta_value as cityLong, 
    service_name.meta_value as service_name, 
    service_address.meta_value as service_address, 
    service_category.meta_value as service_category, 
    service_level.meta_value as service_level, 
    service_info.meta_value as service_info, 
    service_area.meta_value as service_area, 
    service_active.meta_value as service_active, 
    service_keyword.meta_value as service_keyword, 
    ((ACOS(SIN($userLat * PI()/180) * SIN(city_latitude.meta_value * PI()/180) + COS($userLat * PI()/180) * COS(city_latitude.meta_value * PI()/180) * COS(($userLng - city_longitude.meta_value) * PI()/180)) * 180/PI()) * 60 * 1.1515) AS distance 
FROM 
    wp_usermeta AS usermeta 
    LEFT JOIN wp_usermeta as city_longitude ON city_longitude.user_id = usermeta.user_id AND city_longitude.meta_key = 'service_long' 
    LEFT JOIN wp_usermeta as city_latitude ON city_latitude.user_id = usermeta.user_id AND city_latitude.meta_key = 'service_lat' 
    LEFT JOIN wp_usermeta as service_name ON service_name.user_id = usermeta.user_id AND service_name.meta_key = 'service_name' 
    LEFT JOIN wp_usermeta as service_category ON service_category.user_id = usermeta.user_id AND service_category.meta_key = 'service_category' 
    LEFT JOIN wp_usermeta as service_address ON service_address.user_id = usermeta.user_id AND service_address.meta_key = 'service_address' 
    LEFT JOIN wp_usermeta as service_level ON service_level.user_id = usermeta.user_id AND service_level.meta_key = 'wp_user_level' 
    LEFT JOIN wp_usermeta as service_info ON service_info.user_id = usermeta.user_id AND service_info.meta_key = 'service_additional' 
    LEFT JOIN wp_usermeta as service_area ON service_area.user_id = usermeta.user_id AND service_area.meta_key = 'service_area' 
    LEFT JOIN wp_usermeta as service_active ON service_active.user_id = usermeta.user_id AND service_active.meta_key = 'active' 
    LEFT JOIN wp_usermeta as service_keyword ON service_keyword.user_id = usermeta.user_id AND service_keyword.meta_key = 'service_keywords' 
    INNER JOIN wp_users ON wp_users.ID = usermeta.user_id 
WHERE (service_name.meta_value != '' AND service_name.meta_value != 'Anonymous') AND service_level.meta_value = 0 AND service_active.meta_value = 1 
HAVING distance < $search_distance 
ORDER BY distance ASC 
+3

での発言を削除する必要がありますか?私達にこれを示してください。フル・テーブル・スキャンが必要な結合がありますか?また、WHERE条件を適切なONパーツに追加する必要があります。 – Seb

+0

@P Heron - いくつかのサンプル日付でテーブルから作成を投稿できますか? wp_usermetaに1回以上参加する必要はありません。 http:// sqlfiddleでデータを送信すると、私はあなたに問い合わせを行います。com/ –

+0

@Bernd Buffen - それは大変ありがとうございます。私は[link](http://sqlfiddle.com/#!9/af672a)でいくつかのデータをセットアップしました。これまでにそれを使用したことはありませんでした。 –

答えて

0

LEFT JOIN wp_usermeta as city_longitude ON city_latitude.user_id = city_longitude.user_id AND city_longitude.meta_key = 'service_long' 

ので、あなたはこれを試すことができます。あなたが私にさらにデータを送るなら、私はより多くのクエリを最適化することができます 速度のために。計算は距離から変更する必要があります。私が与える何をEXPLAINんテストのためのconst(2)でPHPの値を交換しても有するライン

SELECT 
    res.* 
    ,((ACOS(SIN(2 * PI()/180) * SIN(cityLat * PI()/180) 
    + COS(2 * PI()/180) * COS(cityLat * PI()/180) 
    * COS((2 - cityLong) * PI()/180)) * 180/PI()) * 60 * 1.1515) AS distance 
    FROM (
     SELECT 
      wpu.ID 
      , wpu.user_email 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_lat'   ,wpm.meta_value,'') SEPARATOR '') AS cityLat 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_long'   ,wpm.meta_value,'') SEPARATOR '') AS cityLong 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_name'   ,wpm.meta_value,'') SEPARATOR '') AS service_name 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_address'  ,wpm.meta_value,'') SEPARATOR '') AS service_address 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_category'  ,wpm.meta_value,'') SEPARATOR '') AS service_category 
      , GROUP_CONCAT(if(wpm.meta_key = 'wp_user_level'   ,wpm.meta_value,'') SEPARATOR '') AS service_level 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_additional' ,wpm.meta_value,'') SEPARATOR '') AS service_info 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_area'   ,wpm.meta_value,'') SEPARATOR '') AS service_area 
      , GROUP_CONCAT(if(wpm.meta_key = 'active'     ,wpm.meta_value,'') SEPARATOR '') AS service_active 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_keywords'  ,wpm.meta_value,'') SEPARATOR '') AS service_keyword 
    FROM wp_users AS wpu 
    LEFT JOIN wp_usermeta as wpm ON wpm.user_id = wpu.id  
    GROUP BY wpm.user_id 
) as res 
WHERE 
    (res.service_name != '' AND res.service_name != 'Anonymous') 
    AND res.service_level = 0 
    AND res.service_active = 1 
-- HAVING distance < $search_distance 
ORDER BY distance ASC; 

結果

ID user_email meta_key cityLat cityLong service_name service_address service_category service_level service_info service_area service_active service_keyword distance 
2 [email protected] wp_user_level 54.90131 -1.385126 service2 7 address1 address2 Support Info and Advice|Health and Wellbeing|Things to do|Education Training|Volunteering 0 A strong, local, independent charity working with and for older people (those 50+) Sunderland 1  3659.9253142487732 
3 [email protected] wp_user_level 54.897923 -1.514989 service 3 6 address1 address2 Support Info and Advice|Children Young people and Families|Health and Wellbeing|Things to do|Housing and your home|Education Training|Employment|Volunteering|Money Matters|Mental Health|Cultural 0 is a local independent charity offering a range of mental health and wellbeing services and training for the local community throughout . Sunderland 1  3660.080614342941 
+0

ありがとう、私はそれを試して、それが行く方法を教えてあげる –

+0

それは私が期待してよりよく働いた、クエリは0.09秒程度まで今ダウンです。助けてくれてありがとう。 –

0

あなたのクエリはかなり巨大だと思います。ワードプレスでは、小さな部分に分割してその結果を組み合わせることができるかどうかはわかりません。

このクエリーを保持したい場合は、1)参加している必要な列にインデックスがあることを確認すること2)where句に必要な列がインデックスされていることを確認することをお勧めします。

必要な列:実際には、結合のすべての列にインデックスを挿入できますが、挿入速度は遅くなります。 だから、巨大なテーブルに属するカラムにインデックスを置くことができます。

1

ON部分にwhere条件を直接追加する必要があります。それ以外の場合は、最初に何か(これは巨大です)に参加し、それを減らします。したがって、参加するときに直接減らすことができます。シャードははるかに高速です。

+0

これはMySQLでは当てはまりません。結合の条件は 'WHERE'節の条件と同じように最適化されます。実際には、 'WHERE'節に条件を入れると暗黙的に' LEFT JOIN'が 'INNER JOIN'に変わってしまいますが、OPの質問にはそれが正しいと思います。 –