线上老代码,订单查询页面,查询一百个订单的详情,产生上万条SQL语句,使用模型预加载,解决n+1次查询的问题();
tips:
Prepare在execute阶段可以节省硬解析的时间。如果sql只执行一次,且以prepare的方式执行,
那么sql执行需两次与服务器交互(Prepare和execute), 而以普通(非prepare)方式,
只需要一次交互。这样使用prepare带来额外的网络开销,可能得不偿失。我们再来看同一sql执行多次的情况,
比如以prepare方式执行10次,那么只需要一次硬解析。这时候 额外的网络开销就显得微乎其微了。
因此prepare适用于频繁执行的SQL。
Prepare的另一个作用是防止sql注入
//hidden()方法,在查询的时候加了field()方法的情况下,对所有数据可用(5.1.39版的ThinkPHP)
//关联方法,关联键,一定要包含在field()方法里面
//模型的getTypeAttr()方法,会覆盖type字段(原先存在type字段);
//模型的getCnTypeAttr()方法,需要在查询后添加append()方法(原先不存在cn_type)字段
//考虑传入''或者 '0'的影响使用is_null(),不可使用empty()
//思考:闭包条件重用------方法调用(放到模型中,组成一个条件,返回一个$query)
//模型中的count函数与SQL中的count不一致,要想达到SQL中count结果,使用field()->select();
//知识盲区 Order::where()为啥不能复用,必须重新调用一次test48()?
// ->cache('orders',100)//若使用缓存结果,键名设计,需要与查询条件挂钩
public function test45()
{
$page = $this->request->param('page', 1);
$page_size = $this->request->param('page_size', 100);
$status = $this->request->param('status', 1);
$type = $this->request->param('type', null);
$order_code = $this->request->param('order_code', null);
$sale_record_number = $this->request->param('sale_record_number', null);
$sale_user = $this->request->param('sale_user', null);
$sale_account = $this->request->param('sale_account', null);
$t1 = microtime(true);
$order_query = $this->test48($order_code, $sale_record_number, $type, $sale_user, $sale_account);
//获取某个状态的详情列表
$re = $order_query->where('status', '=', $status)
->field('id,order_code,sale_id,account_id,shipping_service_id,buyer_name,buyer_tel,buyer_email,
buyer_address1,buyer_address2,buyer_country_id,buyer_city,buyer_state,buyer_postcode,status,
sale_record_number,customer_code,tracking_number,currency_id,add_time,paid_time,send_time,remarks,type,pp_transaction_id')
->order('id', 'desc')
->page($page, $page_size)
->select();
//知识盲区,为啥这里必须重新调用一次
$order_query = $this->test48($order_code, $sale_record_number, $type, $sale_user, $sale_account);
//获取各个对应条件下, 各状态的统计值
$count_status = $order_query->group('status')->field('status,count(status) as count')->select()->append(['cn_status'])->toArray();
$t2 = microtime(true);
$time1 = $t2 - $t1;
$data = $re->hidden(['id', 'sale_id', 'account_id', 'shipping_service_id', 'buyer_country_id',
'detail' => ['id', 'order_id', 'product_id',
'product' => ['id',
'inventory' => ['id', 'product_id', 'warehouse_id',
'warehouse' => ['id']]]],
'shipping' => ['id', 'warehouse_id', 'warehouse' => ['id']],
'country' => ['id'],
'currency' => ['id'],
'account' => ['id'],
'user' => ['id']])
->append(['cn_type', 'cn_status'])->toArray();
$re = [
'code' => 200,
'msg' => 'success',
'data' => ['time' => $time1, 'count' => $count_status, 'orders' => $data,]
];
return json($re);
}
private function test48($order_code, $sale_record_number, $type, $sale_user, $sale_account)
{
$order_query = Orders::with(['detail' => function ($query_d) {
$query_d->with(['product' => function ($query_p) {
$query_p->with(['inventory' => function ($query_i) {
$query_i->with(['warehouse' => function ($query_wa) {
$query_wa->field('id,name');
}])->field('id,product_id,warehouse_id,quantity,quantity_lock')->where('quantity', '>', 0);
}])->field('id,sku,cn_name');
}])->field('id,order_id,product_code,product_id,quantity,sale_price,other_fee,total_price,item_number,transaction_id');
}, 'shipping' => function ($query_s) {
$query_s->with(['warehouse' => function ($query_w) {
$query_w->field('id,name');
}])->field('id,code,cn_name,warehouse_id');
}, 'country' => function ($query_c) {
$query_c->field('id,cn_name,en_name');
}, 'currency' => function ($query_cu) {
$query_cu->field('id,code,name');
}, 'account' => function ($query_a) {
$query_a->field('account,id');
}, 'user' => function ($query_u) {
$query_u->field('id,name');
}])->where(function ($query) use ($order_code, $sale_record_number, $type, $sale_user, $sale_account){
if (!is_null($order_code)) {
$query->where('order_code', '=', $order_code);
}
if (!is_null($sale_record_number)) {
$query->where('sale_record_number', '=', $sale_record_number);
}
if (!is_null($type)) {
$query->where('type', '=', $type);
}
if (!is_null($sale_user)) {
$query->where('sale_id', '=', $sale_user);
}
if (!is_null($sale_account)) {
$query->where('account_id', '=', $sale_account);
}
});
return $order_query;
}
namespace app\index\model;
use think\Model;
class Orders extends Model
{
public static $types=[0=>'普通订单',1=>'重寄订单',2=>'线下交易',3=>'退件订单',4=>'退款订单',5=>'第三方赔偿'];
public static $status=[0=>'已删除',1=>'未确定',2=>'待检查',3=>'仓储缺货',4=>'直发缺货',
5=>'已确定',6=>'已发货',8=>'已核算',100=>'售价异常',101=>'客户取消'];
//订单与订单子项 hasMany()(订单子项中有order_id)
public function detail(){
return $this->hasMany('OrdersDetail','order_id','id');
}
//订单与国家,belongsTo() (订单中有buyer_country_id)
public function country(){
return $this->belongsTo('Country','buyer_country_id','id');
}
public function shipping(){
return $this->belongsTo('ShippingService','shipping_service_id','id');
}
public function currency(){
return $this->belongsTo('Currency','currency_id','id');
}
public function account(){
return $this->belongsTo('SaleAccount','account_id','id');
}
public function user(){
return $this->belongsTo('User','sale_id','id');
}
//添加额外字段(不覆盖原有的type字段,新增cn_type字段)
public function getCnTypeAttr($value,$data){
return self::$types[$data['type']];
}
public function getCnStatusAttr($value,$data){
return self::$status[$data['status']];
}
}
{
"order_code": "DE********21",
"buyer_name": "F******n",
"buyer_tel": "6*****5",
"buyer_email": "fr*****[email protected]",
"buyer_address1": "2*****ve",
"buyer_address2": "",
"buyer_city": "Peoria",
"buyer_state": "AZ",
"buyer_postcode": "8****8",
"status": 1,
"sale_record_number": "R****8",
"customer_code": "q***r",
"tracking_number": "",
"currency_id": 2,
"add_time": "2019-09-16 03:20:57",
"paid_time": "2019-09-15 21:30:16",
"send_time": "0000-00-00",
"remarks": "",
"type": 0,
"pp_transaction_id": null,
"detail": [
{
"product_code": "V****B",
"quantity": 1,
"sale_price": "12.99",
"other_fee": "0.00",
"total_price": "12.99",
"item_number": "333******77",
"transaction_id": "16*****14",
"product": {
"sku": "VB****B",
"cn_name": "充*******",
"inventory": [
{
"quantity": 28,
"quantity_lock": 0,
"warehouse": {
"name": "东莞仓库"
}
},
{
"quantity": 3,
"quantity_lock": 0,
"warehouse": {
"name": "东莞次品仓"
}
},
{
"quantity": 708,
"quantity_lock": 3,
"warehouse": {
"name": "美国达拉斯二仓"
}
},
{
"quantity": 38,
"quantity_lock": 0,
"warehouse": {
"name": "美国LA仓"
}
}
]
}
}
],
"country": {
"cn_name": "美国",
"en_name": "United States"
},
"currency": {
"code": "USD",
"name": "美元"
},
"account": {
"account": "R***"
},
"user": {
"name": "肖*****"
},
"cn_type": "普通订单",
"cn_status": "未确定"
},