0

データベースが大きいとしましょう。検索結果ページの非常に複雑なクエリがあります。以下のクエリでは、user_profile テーブルからいくつかの属性値 ID を取得していることがわかります。たとえば、教育は 1 つの属性です。属性教育の値 ID がある場合、ID が配列キーである配列 (php コード) からこの ID のラベル名を取得します。

  public static $education        = array(0 => 'No answer', 
                                          1 => 'High school',
                                          2 => 'Some college',
                                          3 => 'In college',
                                          4 => 'College graduate',
                                          5 => 'Grad / professional school',                                    
                                          6 => 'Post grad');     

他の約 10 の属性についても同様です。そうしないと、クエリがさらに複雑になります。テーブル attribute_id_label を作成し、各属性に対して別の結合を作成して、各属性の値 ID のラベル名を取得する必要があります。これは、追加の 10 個の結合を意味し、クエリが遅くなる可能性があります。しかし、それでもこれは正しい方法です。

私の質問は次のとおりです。テーブルattribute_id_labelに約500レコードしかない場合。テーブルが非常に小さいため、このテーブルとの 10 個の結合で大きな違いが生じるでしょうか? テーブル user_profile が非常に大きく、クエリがすでに非常に複雑な場合でも、ご覧のとおり?

そして、ここに私の質問があります:

    SELECT 
    group_concat(DISTINCT looking.looking_for SEPARATOR ',') as lookingFor, 
    group_concat(DISTINCT photo.photo ORDER BY photo.photo_id DESC SEPARATOR ',') as photos, 
    profile.user_id as userId, 
    url as profileUrl, 
    nickname, 
    avatar.photo, 
    city, 
    ethnicity, 
    education, 
    occupation, 
    income, 
    //and 10 more fields like education, occupation, ethnicity...
    FROM user_profile profile 
    LEFT JOIN user_profile_photo photo ON photo.user_id=profile.user_id 
    LEFT JOIN user_profile_photo avatar ON avatar.photo_id=profile.photo_id 
    INNER JOIN user_profile_looking_for looking ON looking.user_id=profile.user_id 
    LEFT JOIN user_profile_txt txt ON txt.user_id = profile.user_id 
    INNER JOIN place a ON a.place_id=profile.place_id 
    INNER JOIN (SELECT lat, lon FROM place WHERE place_id = :place_id) b ON (3959 * acos( cos( radians(b.lat) ) * cos( radians( a.lat ) ) * cos( radians( a.lon ) - radians(b.lon) ) + sin( radians(b.lat) ) * sin( radians( a.lat ) ) ) ) < :within 
    GROUP BY profile.user_id LIMIT 0,12 

ほとんどの属性はユーザーによって入力されません。NULL 不可をアドバイスしたので、これらの未入力の属性に使用するのに最適なものは何ですか? 各属性の追加フィールドに使用できます 回答なし。各属性には追加の値があります。答えはありません。たとえば、属性の教育と欲求を与えましょう。属性の教育の ID は 1、欲求は 2 です。

eav_attribute_option 
option_id | attr_id | label 
1 | 1 | No answer 
2 | 1 | High school 
3 | 1 | ...  
4 | 2 | No answer 
5 | 2 | Opportunities 
6 | 2 | ... 

しかし今、問題は繰り返されています 各属性の答えの値はありません。しかし、これは NULL 値を回避する方法です。これが正しいかどうかはわかりません。

4

3 に答える 3

1

私はこの種のコードリスト作業を数多く行ってきました。通常、それはパフォーマンスを向上させるのに役立ちます。@alxklx は、コードリスト テーブル (教育など) が適切に形成されていることを確認する必要があるという真実を指摘しました。あれは、

  • education_id 列は、codelist テーブル内の一意の主キーである必要があります。
  • education_id 列は単純なプリミティブ データ型である必要があります。つまり、またはのint代わりにします。decimalvarchar
  • Education_id がデータ テーブルに表示される場合、それは codelist テーブルで使用するのと同じデータ型である必要があり、NULL 不可である必要があります。つまり、欠落データを示すためにデータ テーブルで NULL を使用しないでください。

これらのことを行うと、JOIN はこのように単純に見えます

  FROM people p
  JOIN education e ON p.education_id = e.education_id

RDBMS のオプティマイザは、それらが単純な 1:1 結合であることを認識しています。

とはいえ、複雑なクエリは、ライブ システムに配置する前に、機能とパフォーマンスの両方を調べる必要があります。

データが欠落している場合peopleは、ゼロまたは 1 の Education_id (またはその他の attribute_id) を使用してください。ID が 0 または 1 で、値が「不明」または「ユーザーが教えてくれなかった」など、意味のある行を各 codelist テーブルに入れます。(アプリケーションの利便性に基づいて、0 または 1 のいずれかを選択できます。私は 0 を好みますが、それは個人的な好みです。)

于 2013-02-04T13:44:04.940 に答える
0

一般に - 非常に一般的な - 外部キー関係での結合 - つまり、attribute_id が実際に主キーであり、対応するインデックスがあり、INT のようなインデックスに適したデータ型を使用している場合、結合を効果的に自由に扱うことができます。パフォーマンスの観点。

調べる最善の方法は、それを試して、何が起こっているのかを EXPLAIN に尋ねることです。

于 2013-02-04T14:05:31.680 に答える
0

考慮する必要がある 2 つの重要な点は、まずテーブルと 2 番目のインデックスの大きさです。大きなテーブルにインデックスがない場合、またはフィールドのデータ型が結合先のテーブルのフィールドのデータ型と異なる場合は、数日または数か月かかることもあります。個人的には、巨大なテーブルではるかに大きな選択を行ったことがありますが、結果はかなり良好で、約 2 秒でした。Explain Select を使用して、クエリの状態を確認し、何か問題がある場合は、テーブルを説明し、それらのインデックスを表示して比較します。データベースの設計がわからない場合、決定的な答えを出すのは本当に難しいです...

于 2013-02-04T13:16:27.873 に答える