MySQL在复杂查询中加入了具有大表的小表 - 它们有多消耗?

时间:2013-02-04 12:58:19

标签: mysql database performance database-design join

我们假设数据库很大。我对搜索结果页面有一个非常复杂的查询。在下面的查询中,您可以看到我从user_profile表中检索了一些属性值ids,例如,education是一个属性。当我有属性教育的值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个连接可能会减慢查询速度。但这仍然是正确的方法。

所以我的问题是: 如果table 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 

大多数属性都不会被用户填充,因为您建议使用非NULLable,那么对于那些未填充的属性最好使用哪些属性?我可以使用每个属性额外的字段没有答案。每个属性都有额外的值无答案。让我们给出属性教育和想要的例子。属性教育有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值的方法。我不确定这是否正确。

3 个答案:

答案 0 :(得分: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中缺少数据,请使用0或1的education_id(或其他一些attribute_id)。在每个代码列表表中添加一行,其中id为0或1,值为“unknown”或“user not not告诉我们”或任何有意义的行。 (您可以根据应用程序的便利性选择零或一。我更喜欢零,但这只是个人偏好。)

答案 1 :(得分:0)

您需要考虑的两件非常重要的事情 - 首先是表和第二索引有多大。如果大型表上缺少索引,或者该字段的数据类型与表的字段的数据类型不同,则将其加入 - 它可能需要数天甚至数月。就个人而言,我已经用巨大的桌子做了更大的选择,结果非常好,大约2秒钟。使用explain select来查看查询是如何站立的,如果某些内容不正确 - 请描述您的表,显示其索引并进行比较。如果我们不了解您的数据库设计,那么很难给出明确的答案......

答案 2 :(得分:0)

一般而言 - 非常非常通用 - 加入外键关系 - 即attribute_id确实是主键,具有相应的索引,具有像INT这样的索引友好数据类型,您可以有效地处理连接从性能的角度来看是免费的。

最好的方法是尝试一下,然后让EXPLAIN告诉你发生了什么。