昨天小伙伴遇到一个联表查询的问题,隐约记得大学的《数据库原理》上有讲过,但是无奈当时只顾着梦游,不记得具体怎么做了,请教前辈后得出三种处理方法。
具体问题:
表A与表B中同时存在某个字段f,现在需要在表A里查找字段f后到表B查询相关数据,这是个很典型且基础的联表查询。
以数据表t_mos和user为例
sel_id | uid | sel_name |
---|---|---|
329 | alpha | 阿尔法 |
330 | beta | 贝塔 |
331 | gamma | 伽马 |
332 | delta | 阿尔法 |
(数据表t_mos)
usr_id | usr_email |
---|---|
alpha | alpha@midea.com |
beta | beta@midea.com |
gamma | gamma@midea.com |
delta | delta@midea.com |
(数据表user)
现在需要查询昵称(sel_name)为‘阿尔法’的用户的邮箱地址(user_email)。
方法一:
left join sql语句查询
1 | $select = "select u.usr_email from t_mos t left join user u on t.uid =u.usr_id where t.sel_name in ('阿尔法');"; |
运行结果
1 | [0]=> |
方法二:
使用的CI的数据库操作类
1 | $query = $this ->MASTER_DB ->where('sel_name','阿尔法') ->join('user', 't_mos.uid =user.usr_id', 'left') ->select('usr_email') ->get('t_mos')->result(); |
运行结果和上面一致
方法三:
分两次查询,在表t_mos中查到uid后再去表user里查usr_email
1 | $resp = $this ->MASTER_DB ->where('sel_name',阿尔法') ->select('uid') ->get("t_mos") ->result_array(); |
运行结果和上面一致
第一种方法直接写sql语句,存在sql注入的风险
第二种方法用CI的数据库操作类join,大表不建议使用,因为使用join进行关联查询,一张表的数据量大时可能会阻塞其他线程的写入操作。
第三种方法分两次查询,需要前端手动处理数据,相比于前两种方法写法稍复杂,但可以优化性能。
把逻辑都放到代码中,数据库就当成 k-v 存储,配合索引,效率更高。 因为数据库服务器比较集中,复杂查询容易出现瓶颈,但是前端代码的服务器,一直都有富裕的,扩充也比较容易。
因此推荐第三种方法。
为了测试三种方法的效率,我往两张数据表里都添加了50W条数据,经过多次测试,结果显示,首次查询耗时比较长,约为100ms,之后都在1ms左右,下面是查询耗时(单位是毫秒ms)
1 | float(147.28403091431) |
测试结果仅供参考。
insert_batch()
另外,在批量插入数据时发现了CI的批量插入数据的数据库类insert_batch()的一个bug,那就是每次插入100条数据,最后返回的affected_rows()只是最后一次的影响条数。CI的insert_batch()部分的源码如下:
1 | for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100) |
要想获取准确的条数只能自己处理了。
参考资料: