使用左连接子查询优化查询以进行搜索

时间:2014-06-16 14:50:38

标签: php mysql join

我的数据库(简化)

inv_assets

| id | manufacturer | type | description
| 1  | HP           | 1    | random string
| 2  | Dell         | 4    | test string

inv_location

| id | asset_id | building | room | user | date_moved
| 1  | 1        | main     | 100  | John | 2014-04-01 
| 2  | 1        | main     | 102  | Henry| 2014-04-20
| 3  | 2        | remote   | 200  | Beth | 2014-05-01
| 4  | 2        | main     | 105  | Jim  | 2014-05-30

项目表中的每个项目在位置表格中都有多个位置,具体取决于项目移动的次数。位置表中的最新日期将是项目的当前位置。

我正在基于此构建搜索。它可以工作,但查询需要很长时间才能完成。现在它需要大约35秒才能执行,但它似乎确实会返回所需的结果。

有没有办法只返回连接中的最新位置并使其运行得更快?

这是典型的查询

SELECT `inv_assets`.*, `inv_location`.`location_id`, `inv_location`.`responsible_user` 
FROM (`inv_assets`) 
LEFT JOIN `inv_location` ON inv_location.id = (SELECT inv_location.id FROM inv_location WHERE inv_location.asset_id = inv_assets.id ORDER BY id DESC LIMIT 1)  
WHERE `location_id` LIKE '%207%'

我正在使用Codeigniter。这是我的搜索功能

function doadvsearch(){
    $search_terms = array();

    $post_data = $this->input->post(NULL, TRUE);
    foreach ($post_data as $key => $value){
        if ($value != ''){
            $search_terms[$key] = $value;
        }
    }

    $this->db->select('inv_assets.*, inv_location.location_id, inv_location._user');
    $this->db->from('inv_assets');
    $this->db->join('inv_location', 'inv_location.id = (SELECT inv_location.id FROM inv_location WHERE inv_location.asset_id = inv_assets.id ORDER BY id DESC LIMIT 1)', 'left', FALSE);

    foreach ($search_terms as $skey => $svalue){
        $this->db->or_like($skey, $svalue);
    }

    if (!empty($search_terms)){
        $query = $this->db->get();
        return $query->result_array();
    }else{
        return array();
    }
}

3 个答案:

答案 0 :(得分:0)

您应该在数据库中的表字段中添加始终使用的列的索引。或者您可以尝试$ this-> db->查询(STRAIGHT QUERY);而不是使用某些功能。

答案 1 :(得分:0)

这会创建一个递归查询,这是问题的根源。实际上,子查询在第一个查询的每一行执行一次。我不确定是否可以避免...

你可以使用GROUP BY来获得更好的表现。例如:

SELECT *,
    (SELECT MAX(date_moved) FROM inv_location AS l 
    WHERE l.asset_id = assets.id)
    AS last_date_moved 
FROM inv_assets AS assets

答案 2 :(得分:0)

找到解决方案并将其写入我的CI功能

function doadvsearch(){
    $search_terms = array();
    $location_fields = array('responsible_user', 'building_id', 'room_no', 'location_id');


    $post_data = $this->input->post(NULL, TRUE);
    foreach ($post_data as $key => $value){
        if ($value != ''){
            $search_terms[$key] = $value;
        }
    }

    $this->db->select('inv_assets.*, lo.location_id, lo.responsible_user');
    $this->db->from('inv_assets');
    $this->db->join('inv_location lo', 'lo.asset_id = inv_assets.id', 'LEFT OUTER', FALSE);
    $this->db->join('inv_location lo2', 'lo2.asset_id = inv_assets.id AND lo.id < lo2.id', 'LEFT OUTER', FALSE);
    $this->db->where('lo2.id IS NULL', NULL, FALSE);

    foreach ($search_terms as $skey => $svalue){
        if (in_array($skey, $location_fields)){
            $skey = "lo.$skey";
        }
        $this->db->or_like($skey, $svalue);
    }

    if (!empty($search_terms)){
        $query = $this->db->get();
        return $query->result_array();
    }else{
        return array();
    }
}
相关问题