有一天,我在循环中查询了数据库,然后我就悲剧了
问题
在开发中,经常会遇到在循环中查询数据库的操作,刚开始的时候觉得没什么。
当数据量大起来后,这种编程方式将会是应用的性能瓶颈。
那么该如何避免不必要的查询呢?
场景
这样一张表
product_props
字段 | 类型 | 备注 |
---|---|---|
id | int | |
product_id | int | 产品id |
pnid | int | 属性Id |
pvid | int | 属性名称id |
有这样一个数据
id | product_id | pnid | pvid |
---|---|---|---|
1 | 1 | 1 | 1 |
2 | 1 | 2 | 2 |
3 | 1 | 3 | 3 |
4 | 1 | 4 | 4 |
5 | 1 | 5 | 5 |
6 | 2 | 6 | 6 |
7 | 2 | 7 | 7 |
8 | 2 | 8 | 8 |
然后来了一组新数据,它需要对产品1进行修改或者写入。
product_id | pnid | pvid |
---|---|---|
1 | 1 | 10 |
1 | 3 | 30 |
1 | 12 | 21 |
1 | 31 | 33 |
如果存在该组数据那么更新,如果不存在那么写入。
方法
- 一般的方法
$product = [
[
'product_id'=>1,
'pnid'=>1,
'pvid'=>10
],
[
'product_id'=>1,
'pnid'=>3,
'pvid'=>30
],
[
'product_id'=>1,
'pnid'=>12,
'pvid'=>21
],
[
'product_id'=>1,
'pnid'=>31,
'pvid'=>33
],
];
foreach ( $product as $p) {
//如果存在则更新
if ( $this->count($p) ) {
$this->update($p);
} else {
$this->insert($p);
}
}
从业务上来说,这么做没问题的。
但是当product_props表的数据量越来越大,而每组数据都去查一次的话,那是非常恐怖的。
那么要如何去避免呢?
- 另一种解决方法
$product = [
[
'product_id'=>1,
'pnid'=>1,
'pvid'=>10
],
[
'product_id'=>1,
'pnid'=>3,
'pvid'=>30
],
[
'product_id'=>1,
'pnid'=>12,
'pvid'=>21
],
[
'product_id'=>1,
'pnid'=>31,
'pvid'=>33
],
];
//获取product_id为1的数据
$oldData = $this->get(1);
/**
* 这里会把数据组成以pnid为键的数组
*/
$oldKeyData = array_column($oldData,NULL,'pnid');
$update = [];
$insert = [];
foreach ( $product as $p) {
if ( isset($oldKeyData[$p['pnid']]) ) {
$updatep[] = $p;
} eles {
$insert[] = $p;
}
}
//进行更新和删除
...
可以看到,这样就完美的避免了在循环中进行查询的操作了。
在开发中,有很多操作是可以通过代码的层面去解决性能问题的,而这需要大家开动大脑了。
也许这个算不得什么干货,已经懂的看看笑笑就好,哈哈哈。
PS:你的赞是我创作的动力!
为什么同是9年义务教育别人就那么优秀?
想知道请关注订阅号:Buger(关注送 laravel,linux,nginx 等学习资料!!!)
回复'学习',推荐你2本书。
本作品采用《CC 协议》,转载必须注明作者和本文链接
@zyy-11 是的
2个数组,互相匹配,一直是我解决这类查询解决方案。我觉得框架类的懒加载也是这么做的。
除了懒加载, model的关联, 列表查询的时候也是走的这个查询,
collect
这个东西有非常多的方法去处理这种数据, 很方便以前我也强迫自己不在循环中做查询,,,各种奇葩业务需求搞来之后,,,就妥协了,,,头发要紧
@largezhou 哈哈哈,明白人
@Bug_tu 看公司项目原本的代码, 有的查个列表 10 条数据, 然后循环查各种数据, 乘起来, 一个请求至少 100 条查询, 响应也很快啊, 也就百来毫秒,,,
等你想尽办法, 怎么在循环外查出所有数据, 然后循环里, 怼到对应的那 10 条数据中, 别人复制粘贴都写了四五个接口了,
反正有时间, 就好好想想怎么写, 没时间, 那只能妥协了,,,
@largezhou 996你懂的
尤其是接手别人留下的项目,公司又让你加一些奇奇怪怪的东西,逻辑怎么简单怎么来,优化的问题,出现慢的情况再说, :joy:
@moder :smirk:
这种循环查询的操作真的还在被很多人使用。 其实有时候只需要一条、两条sql,然后数据自己处理下就可以达到目的。
@MarksGui 是的,一些老项目基本都是这样搞的。。。
这都不算什么,循环里不去查数据库的人会特么循环去查redis,我是真的服,更何况我还在代码里发现了循环调同一个项目里自己的api的操作
@好人二狗 祖传代码无解,直接重构吧 :joy:
之前我也遇到过,写过,被主管骂了,后面老老实实的用in查询 :joy:
@wdnmd :joy: