一、情况描述
我们在做后台数据列表(例如:订单列表、会员列表、活动列表~~之类的)时候,需要的数据往往需要查询两张或以上的数据表,一般情况下会有两种做法
1)联表查询(在这里先不考虑通过联表方法无法查询到想要的字段数据的情况)
2)查单表,循环处理查询其他表的信息
二、两种查询方法比较
针对以上两种情况呢,一般我们都会以为联表查询会比循环查询要快,其实实际情况并不是这样的,其实查单表,再循环查询其他表反而更快
这是为什么呢???其实我也不知道哈哈,下面给出一些我自己的猜测(具体哪个更快,建议各位同学自己动手写一下代码做实验!)
猜测:
1)如果要查询的表数据量比较大,和其他表的关联关系也比较复杂(查一个字段需要关联两张表之类的),这样拼出来的sql语句其实是比较复杂和啰唆的;
2)联表查询的时候,并不像查单表一样(假设查20条数据)直接就查询返回20条记录的,它内部的关联关系比较复杂,例如订单表的member_id关系显示members表的uname,可能并不像我们用member_id来从members表里查询uname一样快捷,它要处理sql里的关联逻辑判断(具体是怎样我也并不懂~~);
3)可能你会说“如果用循环来查询,那不就要执行好多个sql语句(一条记录查一次),mysql连接也消耗大量的资源了吗??”;
4)其实实际上也不完全是这样,mysql连接是要浪费的(下面会有优化方法),不过总查询时间并不会比联表慢。你想一下,当你面对一个很复杂,逻辑很繁琐的问题的时候,相比于硬啃,当复杂问题分解成若干个容易处理的小问题,反而更快
5)以上都是一脸正经地胡说八道,具体性能如何,自己做实验测试!!
三、优化循环查询
上面说到用查单表再循环查询其它表的方法要比联表查询要快,但要消耗比较多的数据库连接,下面我们要说一下如何减少查询次数
1)循环查询的时候,我们一般都是通过一个id去其他表查询我们需要的数据(例如orders表member_id查询members表uname),每循环一次查询一次;
2)其实你有没有发现,每次查询的语句都是一样的??(例如:select uname from members where member_id='xxx'),既然是都一样的,那么我们为什么还要每一次都重复等于等于(=)地来查询??mysql不是还是in这个东西吗??
3)通过上面分析,我们知道,如果是一样的sql语句,只是查询条件值不同的话,干嘛不用in呢??( 例如:select uname from members where member_id in ('1','2') )
4)以上面案例为例的话,其实我们先循环出所以的member_id,再用in一次性查询所有的uname会更快,也只需要查询一次!!!!
5)所以剩下的问题就只是怎么把查询出来的uname再重新分配到每一条记录中去了
6)下面是我的逻辑实现代码, 仅供参考!!!
/** * 更高效的扩展列处理方法 * add by tujia @2016.11.07 * expression(表达式)说明 * 1)前面两个参数是关联表的on条件(例如:rel_id=order_id) * 2)第三个参数是你要提取的字段的名字(例如:t_payed) * 3)示例:rel_id=order_id=t_payed,member_id=member_id=login_account */ protected function nice_row_data(&$data, $sql, $expression){ $ttt = explode('=', $expression); foreach ($data as $key => $value) { $ids[] = $value[$ttt[1]]; } $ids = implode("','", $ids); $sql = sprintf($sql, $ids); $list = $this->db->select($sql); $temp = array(); foreach ($list as $key => $value) { $temp[$value[$ttt[0]]] = $value[$ttt[2]]; } foreach ($data as $key => $value) { $data[$key][$ttt[2]] = isset($temp[$value[$ttt[1]]])? $temp[$value[$ttt[1]]] : 0; } }
使用示例:
$sql = "SELECT `rel_id`,`t_payed` FROM `sdb_ectools_order_bills` ob LEFT JOIN `sdb_ectools_payments` p ON p.`payment_id` = ob.`bill_id` WHERE ob.`rel_id` IN ('%s') AND p.`status`='succ'"; $this->nice_row_data($data, $sql, 'rel_id=order_id=t_payed');
补充说明:$data 是 已经查询出来的 单表数据