不懂就问,这么写,是不是很费资源。。。
原来
$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);
}
计算的可以拿出来在代码中计算
计算部分强烈建议不要在 mysql 中进行
如非不得已,不要使用mysql函数处理sql
是,但是在高版本的 MySQL 中,也添加 GIS 方面的支持,提供了空间索引,比你这样的效率要高。
如果你的 MySQL 还不支持,那如果数据量不大,可以放到代码里面去算,如果数据量稍多,可以放到 Redis 里面,如果数据量巨大,可以放到 ElasticSearch 里面。
为什么又用
join
又用with
?而且这里用
get
,你就已经查询了一次数据了(而且是没有做分页,对所有符合条件的数据都做了一次计算),后面再paginate
是第二次查询。这不慢就有鬼了
。
mysql有现成的计算距离的函数,根本不需要三角函数,
select ST_Distance_Sphere( point(-87.6770458, 41.9631174), point(-73.9898293, 40.7628267) )
合理运用数据库视图可以很好的解耦代码上的复杂度。