近日商城项目功能优化需求,因原来使用传统的php在线导出,当订单量过大时,容易执行超时,需要更改商城相关订单导出业务逻辑,即将在线即时导出改为异步导出,具体实施方案是前端提交导出申请,后台使用python脚本执行导出任务并上传七牛,生成报表下载地址。
通过分析,发现原来报表导出SQL不存在慢查询问题,仅仅是导出量大时执行超时的问题,所以新建了一张导出任务表,将所有导出申请存进去,问题来了,任务在后台执行的时候,怎么知道用户需要导出哪些内容,因为当下订单管理还涉及到许多搜索项,于是乎原先想到的就是将各个搜索条件存成json,然后任务执行的时候,把搜索条件再逐个去拼接,后来发现可行性不大,因为依据不同的搜索条件可能还要关联不同的业务表,瞬间就变复杂了。
这个时候突然想到了如果能把用户的所有导出申请、搜索条件等直接当一条查询SQL存进去岂不方便,这个时候就用到了Laravel打印SQL的方式:
DB::enableQueryLog(); $result['data'] = $query->orderBy($column, $sort)->get(); $sql = DB::getQueryLog();
输出结果:
Array ( [0] => Array ( [query] => select `guider_order`.*, `guider`.`nickname`, `guider`.`mobile`, `guider`.`title` from `guider_order` left join `guider` on `guider`.`id` = `guider_order`.`guider_id` where `guider_order`.`shop_id` = ? and `guider_order`.`order_sn` like ? order by `guider_order`.`created_at` desc [bindings] => Array ( [0] => 1 [1] => %E2017020611031275494% ) [time] => 8.82 ) )
所以在设计的导出任务表里面就直接存进了“query”,以为完事了,最后在取出直接执行的时候脚本报错,才发现遇到坑了,因为这样打印的SQL搜索条件参数的等默认都是“?”替代的,无法直接运行,后来看到数组里面的“bindings”下标,这才发觉查询参数等信息字段都在这个数组下标里面,得通过拼接才能组合成完整的SQL,所以经过一番思忖,采用了如下方式:
DB::enableQueryLog(); $result['data'] = $query->orderBy($column, $sort)->get(); $sql = DB::getQueryLog(); $bindings = $sql[0]['bindings']; echo '<pre>'; print_r($sql); $sqlArr = explode('?', $sql[0]['query']); $exportSql = ''; foreach ($sqlArr as $key => $val) { if(isset($bindings[$key]) && $bindings[$key]) { $joinStr = $bindings[$key]; $exportSql .= $val."'".$joinStr."'"; }else{ $exportSql .= $val; } } print_r($exportSql);
最后$exportSql输出如下:
select `guider_order`.*, `guider`.`nickname`, `guider`.`mobile`, `guider`.`title` from `guider_order` left join `guider` on `guider`.`id` = `guider_order`.`guider_id` where `guider_order`.`shop_id` = '1' and `guider_order`.`order_sn` like '%E2017020611031275494%' order by `guider_order`.`created_at` desc
这就得到了想要的原生SQL,在做任务时直接从当前记录取出执行即可。
涉及到其它优化细则,比如python脚本多进程执行时,可以在WEB端提交导出任务的时候,往redis的LPUSH里面添加,然后通过python连接redis模块来实现队列任务,这个得看后期导出这块的业务时效性要求高不高了,如果要求极快的速度导出报表,那可以考虑现在这种方式。
下面这个是python脚本用到的相关模块
#!/usr/bin/python # -*- coding: utf-8 -*- import os,time,datetime from os.path import join,getsize import MySQLdb #python 2.7 2.6支持 import ConfigParser import logging import csv import codecs import json from random import Random from qiniu import Auth,put_file,etag import qiniu.config import iso8601 import sys reload(sys) sys.setdefaultencoding('utf-8')
去打赏