有一天,我在循环中查询了数据库,然后我就悲剧了

问题

在开发中,经常会遇到在循环中查询数据库的操作,刚开始的时候觉得没什么。

当数据量大起来后,这种编程方式将会是应用的性能瓶颈。

那么该如何避免不必要的查询呢?

场景

这样一张表

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 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 16

2个数组,互相匹配,一直是我解决这类查询解决方案。我觉得框架类的懒加载也是这么做的。

4年前 评论
ruke

除了懒加载, model的关联, 列表查询的时候也是走的这个查询, collect这个东西有非常多的方法去处理这种数据, 很方便

4年前 评论

以前我也强迫自己不在循环中做查询,,,各种奇葩业务需求搞来之后,,,就妥协了,,,头发要紧

4年前 评论
xujinhuan 3年前
adymilk 3年前

@Bug_tu 看公司项目原本的代码, 有的查个列表 10 条数据, 然后循环查各种数据, 乘起来, 一个请求至少 100 条查询, 响应也很快啊, 也就百来毫秒,,,

等你想尽办法, 怎么在循环外查出所有数据, 然后循环里, 怼到对应的那 10 条数据中, 别人复制粘贴都写了四五个接口了,

反正有时间, 就好好想想怎么写, 没时间, 那只能妥协了,,,

4年前 评论
DarthVader 4年前
moder

尤其是接手别人留下的项目,公司又让你加一些奇奇怪怪的东西,逻辑怎么简单怎么来,优化的问题,出现慢的情况再说, :joy:

4年前 评论

这种循环查询的操作真的还在被很多人使用。 其实有时候只需要一条、两条sql,然后数据自己处理下就可以达到目的。

4年前 评论

@MarksGui 是的,一些老项目基本都是这样搞的。。。

4年前 评论

这都不算什么,循环里不去查数据库的人会特么循环去查redis,我是真的服,更何况我还在代码里发现了循环调同一个项目里自己的api的操作

4年前 评论

@好人二狗 祖传代码无解,直接重构吧 :joy:

4年前 评论

之前我也遇到过,写过,被主管骂了,后面老老实实的用in查询 :joy:

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!