不懂就问,这么写,是不是很费资源。。。

原来#

$merchants = Merchant::where('ident_status',10)
                        ->select('id', 'company_name', 'store_pic', 'goods_category', 'location_name', 'latitude', 'longitude')
                        ->selectRaw(\DB::raw('(6371 * acos(cos(radians(' . $userLatitude . ')) * cos(radians(latitude)) * cos(radians(longitude) - radians(' . $userLongitude . ')) + sin(radians(' . $userLatitude . ')) * sin(radians(latitude)))) AS distance'))
                        ->with('merchant_goods:id,merchant_id,merchant_goods_total_price,merchant_goods_sell_price,merchant_goods_title')
                        ->orderBy('created_at', 'desc')
                        ->paginate(10);

其中,下面是在算用户和商户的实时距离

selectRaw(\DB::raw('(6371 * acos(cos(radians(' . $userLatitude . ')) * cos(radians(latitude)) * cos(radians(longitude) - radians(' . $userLongitude . ')) + sin(radians(' . $userLatitude . ')) * sin(radians(latitude)))) AS distance'))

现在更复杂了#

merchant 和 merchant_goods 两张表,要在 merchant 计算距离,要在 merchant_goods 统计商户的所有商品销量,还要列出 merchant 对应的所有 merchant_goods,

$merchantsQuery = Merchant::join('merchant_goods', 'merchants.id', '=', 'merchant_goods.merchant_id')
                    ->where('merchants.ident_status', 10)
                    ->has('merchant_goods')
                    ->select('merchants.id', 'merchants.user_id', 'merchants.company_name', 'merchants.store_pic', 'merchants.goods_category', 'merchants.location_name', 'merchants.latitude', 'merchants.longitude')
                    ->selectRaw(\DB::raw('(6371 * acos(cos(radians(' . $userLatitude . ')) * cos(radians(merchants.latitude)) * cos(radians(merchants.longitude) - radians(' . $userLongitude . ')) + sin(radians(' . $userLatitude . ')) * sin(radians(merchants.latitude)))) AS distance'))
                    ->selectRaw('SUM(merchant_goods.fake_sell_count) AS fake_sell_count')
                    ->groupBy('merchants.id', 'merchants.user_id', 'merchants.company_name', 'merchants.store_pic', 'merchants.goods_category', 'merchants.location_name', 'merchants.latitude', 'merchants.longitude')
                    ->with('merchant_goods:id,merchant_id,merchant_goods_total_price,merchant_goods_sell_price,merchant_goods_title');

        if($category == 'default') {
            $merchantsQuery->orderBy('merchants.created_at', 'desc');
        }

        if($category == 'lbs') {
            $merchantsQuery->orderBy('distance', 'asc');
        }

        if($category == 'sell') {
            $merchantsQuery->orderBy('fake_sell_count', 'desc');
        }

        $merchants = $merchantsQuery->paginate(7);

model 优化版 (计算在 model 里了,但是速度更慢了,同时 100 条 1.2s,直接写 sql 里算 900ms 左右)#

public function list(Request $request) {

        $category = $request->category;

        $userLatitude = $request->latitude;

        $userLongitude = $request->longitude;

        //select、with的时候id或者ORM匹配的字段一定要有,不然with会失效
        $merchantsQuery = Merchant::join('merchant_goods', 'merchants.id', '=', 'merchant_goods.merchant_id')
                    ->where('merchants.ident_status', 10)
                    ->has('merchant_goods')
                    ->select('merchants.id', 'merchants.user_id', 'merchants.company_name', 'merchants.store_pic', 'merchants.goods_category', 'merchants.location_name', 'merchants.latitude', 'merchants.longitude')
                    ->selectRaw('SUM(merchant_goods.fake_sell_count) AS fake_sell_count')
                    ->groupBy('merchants.id', 'merchants.user_id', 'merchants.company_name', 'merchants.store_pic', 'merchants.goods_category', 'merchants.location_name', 'merchants.latitude', 'merchants.longitude')
                    ->with('merchant_goods:id,merchant_id,merchant_goods_total_price,merchant_goods_sell_price,merchant_goods_title');

        // 在这里输出$merchants之前,可以对其进行遍历,计算每个商家距离用户的距离
        foreach ($merchantsQuery->get() as $merchants) {
            $merchants->distance; // 访问距离属性,会触发getDistanceAttribute()方法进行计算
        }

        if($category == 'default') {
            $merchantsQuery->orderBy('merchants.created_at', 'desc');
        }

        if($category == 'lbs') {
            $merchantsQuery->orderBy('merchants.distance', 'asc');
        }

        if($category == 'sell') {
            $merchantsQuery->orderBy('fake_sell_count', 'desc');
        }

        $merchants = $merchantsQuery->paginate(100);

        return response()->json(['data' => $merchants],201);

    }
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 14

计算的可以拿出来在代码中计算

2年前 评论

计算部分强烈建议不要在 mysql 中进行

2年前 评论
wongvio (楼主) 2年前
23tl (作者) 2年前
wongvio (楼主) 2年前
it_cwc 2年前
wongvio (楼主) 2年前
pi_phq 2年前
王小大 2年前
gongmeng

如非不得已,不要使用 mysql 函数处理 sql

2年前 评论

是,但是在高版本的 MySQL 中,也添加 GIS 方面的支持,提供了空间索引,比你这样的效率要高。

如果你的 MySQL 还不支持,那如果数据量不大,可以放到代码里面去算,如果数据量稍多,可以放到 Redis 里面,如果数据量巨大,可以放到 ElasticSearch 里面。

2年前 评论

为什么又用 join 又用 with

而且这里用 get ,你就已经查询了一次数据了(而且是没有做分页,对所有符合条件的数据都做了一次计算),后面再 paginate 是第二次查询。

 foreach ($merchantsQuery->get() as $merchants) 

这不慢就有鬼了:joy:

2年前 评论

mysql 有现成的计算距离的函数,根本不需要三角函数,

select ST_Distance_Sphere( point(-87.6770458, 41.9631174), point(-73.9898293, 40.7628267) )

2年前 评论

合理运用数据库视图可以很好的解耦代码上的复杂度。

2年前 评论