thinkphp5.0的查询方法 where in 性能问题以及优化措施

最近在后台导出数据到Excel,考虑到可能数据量大使用了c扩展xlswriter来做Excel处理,首先在本地测试,1w条数据花费了40s,不太理想。

thinkphp 版本为 5.0.4

于是想知道在哪一步花费的时间比较多,打断点日志发现,导出过程只花了1秒,处理数据也只花了2s,但是有一个查询却花了36s,然后日志文件记录的该sql执行时间只有零点几秒,于是将这个sql拿到navicate执行,发现也只需要0.3s,好吧,找到原因了,应该是在组装sql的时候耗时较长。我的查询是这样的:

$users = $this->opDataModel->setTable('read3_user_data')->where('activity_id', $activityId)
->where('userid', 'in', array_keys($scoreArr))
->field('departid, userid, score, updatetime, nickName, userName, phone')->select();

其中 array_keys($scoreArr) 是获取到 userid 的数组,有1w个元素,经测试这个函数耗时可以忽虐不计。

既然纯sql的执行时间很短,那么可以尝试使用query方法来执行拼接好的sql是不是会好一些,修改如下:

$sql = "select departid, userid, score, updatetime, nickName, userName, phone from read3_user_data where activity_id={$activityId} and userid in (".join(',', array_keys($scoreArr)).")";
$users = $this->opDataModel->query($sql);

发现这个方法的耗时在0.5s,得到的结果集是一样的,我去,差别这么大的吗??

经过调试才知道问题发生在where方法在拼接sql的过程中,它会生成参数绑定表达式sql和一个大的bind数组,而in后面的每一个元素被当做一个参数位置来绑定,元素越多耗时越多。

public function query($sql, $bind = [], $master = false, $class = false)
{
	return $this->connection->query($sql, $bind, $master, $class);
}

而使用纯sql的形式就是绕过了参数绑定,但是如果参数来自用户输入就会存在一定的注入风险,在我们这个场景下是完全可以使用纯sql的。

既然如此我们也可以在原来的基础上优化:

$users = $this->opDataModel->setTable('read3_user_data')->where('activity_id', $activityId)
->where('userid in ('.join(',', array_keys($scoreArr)).')', 'in', array_keys($scoreArr))
->field('departid, userid, score, updatetime, nickName, userName, phone')->select();

发现耗时降到0.5s。

于是想到去测试一下 lumen 框架是不是也是这样的。

public function testGetList()
{
	$ids = '...'; // 1w 个userid
	$start = microtime(true);
    Read3UserData::where('activity_id', 63)->whereIn('userid', explode(',', $ids))->get();
    $this->info(microtime(true)-$start);
    
	$this->info($list->count()); // 10000
}

耗时才 3s,看来 lumen 并不存在这样的问题啊。

使用纯sql试一下:

public function testGetList()
{
	$ids = '...'; // 1w 个userid
	$start = microtime(true);
    Read3UserData::where('activity_id', 63)->whereRaw('userid in ('.$ids.')')->get();
    $this->info(microtime(true)-$start);

	$this->info($list->count()); // 10000
}

耗时 0.7s

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值