0

假设数据库很大。我对搜索结果页面有一个非常复杂的查询。在下面的查询中,您可以看到我从 user_profile 表中检索了一些属性值 id,例如,教育是一个属性。当我有属性教育的值 id 时,我从数组(php 代码)中检索此 id 的标签名称,其中 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 

大多数属性不会由用户填充,并且由于您建议不可为空,对于那些未填充的属性最好使用什么?我可以为每个属性使用额外的字段没有答案。每个属性都会有额外的价值没有答案。让我们以属性教育和想要为例。属性教育有 id 1,want 是 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 列应该是一个简单的原始数据类型。也就是说,将其设为 anint而不是 adecimalvarchar
  • 当education_id 出现在您的数据表中时,它必须与您在codelist 表中使用的数据类型相同,并且它必须不可为NULL。换句话说,不要在数据表中使用 NULL 来表示缺失数据。

如果你做这些事情,你的 JOIN 看起来就这么简单

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

RDBMS 的优化器知道它们是简单的 1:1 连接。

话虽如此,在将任何复杂查询放入实时系统之前,都需要检查其功能和性能。

如果您在people使用中缺少数据,则education_id(或其他一些attribute_id)为零或一。在每个代码列表表中放置一行,id 为 0 或 1,值为“未知”或“用户没有告诉我们”或任何有意义的值。(您可以根据应用程序的便利性选择零或一。我更喜欢零,但这只是个人喜好。)

于 2013-02-04T13:44:04.940 回答
0

您需要考虑的两个非常重要的事情 - 首先是表和第二个索引有多大。如果一个大表上缺少索引,或者字段的数据类型与你加入它的表的字段的数据类型不同——这可能需要几天甚至几个月的时间。就我个人而言,我用巨大的桌子完成了更大的选择,结果非常好,大约 2 秒。使用解释选择来查看查询的状态,如果有问题,请描述您的表,显示它们的索引并进行比较。如果我们不了解您的数据库设计,真的很难给您一个明确的答案......

于 2013-02-04T13:16:27.873 回答
0

一般来说 - 非常非常一般 - 在外键关系上连接 - 即,attribute_id 确实是主键,具有相应的索引,具有索引友好的数据类型(如 INT),您可以将连接视为有效地没有性能角度。

找出答案的最佳方法是尝试并要求 EXPLAIN 告诉您发生了什么。

于 2013-02-04T14:05:31.680 回答