有没有比做几个JOINS(MySQL)更有效的方法?

时间:2009-10-14 17:02:41

标签: sql mysql query-optimization

我有三张桌子:

  1. USER: user_id (pk); username
  2. FIELD: field_id (pk); name
  3. METADATA: metadata_id (pk); field_id (indx); user_id (indx); value
  4. 这样做的原因是应用程序允许为每个用户创建自定义字段。要显示用户的所有信息,我正在构建一个动态查询(通过PHP),最终看起来像这样:

    SELECT
      u.username, m1.value AS m1value, m2.value AS m2value
    FROM user AS u
    LEFT JOIN metadata AS m1
      ON (u.user_id=m1.user_id AND m1.field_id=1)
    LEFT JOIN metadata AS m2
      ON (u.user_id=m2.user_id AND m2.field_id=2)
    

    此示例只有2个用户元数据字段,但您可以了解如果有十几个字段,这会是什么样子。

    还有另一种更好的方法来编写此查询吗?随着用户和元数据字段的增长,我担心这个查询的性能。

    修改 我想在返回的结果中每行有一个用户。

5 个答案:

答案 0 :(得分:2)

为什么不立刻抓住它们?

SELECT u.user_id,u.username, m.field_id,m.value FROM user u
LEFT JOIN metadata m
ON u.user_id=m.user_id 
WHERE 1 ORDER BY user_id

或针对特定用户:

SELECT u.user_id,u.username, m.field_id,m.value FROM user u
LEFT JOIN metadata m
ON u.user_id=m.user_id 
WHERE user_id = ? ORDER BY user_id

除了被索引之外,请确保user_id在两个表之间的类型和长度完全相同,或者您仍然最终进行表扫描。

您的服务器代码是什么语言?

每个用户获得一行(kinda)的一种简单方法是在循环中返回行,检查每个user_id是否与最后一行相同。如果没有,新行。<​​/ p>

while ( $row = $sth->fetch_object() ) {
  $previous_user_id = '';
  if ( $row->user_id != $previous_user_id ) {
    # new row
  } else {
    # not new row
  }
  $previous_user_id = $row->user_id;
}

答案 1 :(得分:0)

您必须有两个查询。一个用于用户追溯(SELECT * FROM users),然后另一个用于提取用户的自定义字段(SELECT * FROM fields WHERE users_id = user_id)。

在某些情况下,您可以通过一个查询将其拉出来......告诉我们更多关于您将要追求的结果的详细信息。

答案 2 :(得分:0)

您通常每行返回一个元数据元素,如:

SELECT u.username, mi.field_id, m1.value
FROM user AS u
LEFT JOIN metadata AS m1 ON u.user_id = m1.user_id

这应该可以在数千名用户中执行。

答案 3 :(得分:0)

你可能会尝试类似......

SELECT
    u.username,
   (SELECT TOP 1 m.value
    FROM metadata m
    WHERE u.user_id=m.user_id AND m.field_id=1),
   (SELECT TOP 1 m.value
    FROM metadata m
    WHERE u.user_id=m.user_id AND m.field_id=2)
FROM user AS u

......但是你的表现可能与你的表现相似(也可能更差)。如果遇到性能问题,请检查以确保user_id和field_id都已建立索引。

答案 4 :(得分:0)

(正如评论者所指出的,这在MySQL中无效,所以,对不起。但如果你有兴趣:)

如上所述,对元数据表执行一次JOIN,然后使用PIVOT将每个用户的多行更改为一行,其中包含许多列,每个字段一个。我认为这在SQL Server 2005及更高版本中有效。