【问题标题】:Advanced MySQL Joining. Speeding up query高级 MySQL 连接。加快查询
【发布时间】:2012-02-07 06:08:28
【问题描述】:

我的 php 应用程序上有一个用户列表(使用 codeigniter)。每个用户可能已经完成了一个包含大约 1000 个左右字段的表单。结构看起来类似于这样:

用户

id|username|...

completed_form_fields

id|formid|userid|fieldkey|data

其中字段键只是该特定表单字段的唯一键,即:“first_name”

我有一个用户搜索页面,人们可以通过他们选择的字段(眼睛颜色、种族、性别......)过滤掉特定用户然后我需要显示这些字段,以便我喜欢(并且目前有)输出像这样:

$filteredmembers = array(
[0] = Object(
   [id] => 1
   [username] => kilrizzy
...
   [fields] => Array(
        [fname] => Jeff
        [gender] => Male
        ...

目前我的脚本显然要花很长时间,因为我查询了所有填写此表单的成员,然后遍历每个成员以查询他们的所有字段。然后根据条件+页面/偏移量过滤掉那些。

我知道需要有一种方法可以在一个我不熟悉的查询中将它们连接在一起

我的非常慢的代码的简化版:

function get_members(){
    $this->db->select('u.*');
    $this->db->from('users AS u');
    $query = $this->db->get();
    if ($query->num_rows() > 0){
        $members = $query->result();
        //Get fields from each user
        foreach($members as $mk => $mv){
            $fields = $this->get_form_fields($mv->id,1,true);
            $members[$mk]->fields = $fields;
        }
        return $members;
    }else{
        return false;   
    }
}
function get_form_fields($uid,$form,$values=false){
    $this->db->where('user', $uid); 
    $this->db->where('form', $form); 
    $query = $this->db->get('form_fields');
    if ($query->num_rows() > 0){
        $result = $query->result();
        return $result;
    }else{
        return false;   
    }
}

【问题讨论】:

  • 您的过滤条件应该是 WHERE 子句的一部分,该子句是根据 completed_form_fields 表中的信息动态构建的。我无法想象您在尝试什么,但您可能还需要在 users 和 completed_form_fields 表之间进行 INNER JOIN。
  • @bfavaretto - 添加了我的查询示例

标签: php mysql codeigniter join


【解决方案1】:

有一种方法,但是添加的字段越多,它就会变得越昂贵。许多选择以这种形式存储附加用户数据的 CMS 也会发生同样的情况。

您可以使用以下方法获得有效的搜索 SQL:

SELECT
    users.*,
    firstname.data AS firstname,
    lastname.data AS lastname,
    eyecolor.data AS eyecolor,

FROM
    users
    LEFT JOIN completed_form_fields AS firstname ON firstname.userid = users.id AND firstname.fieldkey = "firstname"
    LEFT JOIN completed_form_fields AS lastname ON lastname.userid = users.id AND lastname.fieldkey = "lastname"
    LEFT JOIN completed_form_fields AS eyecolor ON eyecolor.userid = users.id AND eyecolor.fieldkey = "eyecolor"

WHERE
    firstname.data LIKE '%searchdata%'
    OR lastname.data LIKE '%searchdata%'
    OR eyecolor.data LIKE '%searchdata%'

添加表越多,这种方法对于 MySQL 服务器来说就变得非常庞大和昂贵。因此,我建议不要超过 10-15 次这样的连接,然后我会再次对其进行分析以确保。

【讨论】:

  • 这看起来像我需要这样做。我希望有一个我不知道的神奇解决方案。谢谢!
【解决方案2】:
SELECT u.username, f.formid, f.userid, f.fieldkey, f.data FROM user AS u
LEFT JOIN completed_form_fields AS f
ON f.userid = u.id


you should look at indexing your userid, index(userid), via phpmyadmin or sql file

mysql-indexes

【讨论】:

    【解决方案3】:

    我不确定我是否完全理解这个问题。您可以使用单个查询来获取所有用户及其所有字段(基本上,这是 Philip 建议的):

    SELECT u.username, f.* 
    FROM user AS u
        INNER JOIN completed_form_fields AS f
        ON f.userid = u.id
    ORDER BY u.id, f.fieldkey
    

    要过滤结果,请添加带有条件的WHERE 子句。例如,仅从fieldkeys 'k1'、'k2' 和 'k3' 获取数据:

    SELECT u.username, f.* 
    FROM user AS u
        INNER JOIN completed_form_fields AS f
        ON f.userid = u.id
    WHERE f.fieldkey IN ('k1', 'k2', 'k3')
    ORDER BY u.id, f.fieldkey
    

    这是你要找的吗?

    【讨论】:

      猜你喜欢
      • 2017-01-12
      • 2015-10-15
      • 1970-01-01
      • 2018-05-17
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 2013-03-29
      相关资源
      最近更新 更多