当前位置: 首页 > news >正文

php性能优化之不要在for循环中操作DB

如何提高程序运行速度,减轻服务器压力是服务端开发必须面对的一个问题。

简单且朴素的原则:不要在for循环中操作DB,包括关系型数据库和NoSql。

我们应该根据自己的业务场景,在for循环之前批量拿到数据,用尽量少的sql查询批量查到结果。 在for循环中进行数据的匹配组装。

场景说明

  • 业务在多个情景下需要获得用户的详细信息,有点可以通过查询用户表直接获取到,有的需要查询关联关系表获取到,有的只保存了关联的id,并没有单独创建关联关系表,需要单独写获取函数取值。
  • 既然多个场景下需要调用,那么封装成一个公共方法,让多个场景统一调用公共方法是基本的优化思路。
  • 上面提到了复杂的存取值关系,我们需要分析一下,哪些操作是耗时的,耗时的操作如何优化,能否减少sql查询的次数。

举例说明

  • 下面的代码示例,我们封装了 CommonRender 的类,所有可以统一输出的方法都在这里
  • 下面代码标注了优化之前优化之后
  • 优化之前:在每次查询都需要根据保存的id,去数据库查询;如果列表页每次返回30条数据,那这部分就需要30次sql查询。
  • 优化之后:采用的是提前批量取值,又写了一个函数 _renderHobby ,只需要1次sql。
  • 这样就极大的减少了sql查询,提高了程序响应的速度。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

<?php

namespaceApp\Render;

.

.

.

classCommonRenderextendsBaseRender

{

publicstaticfunctionrenderUserinfo($data,$hobbyInfo= [])

{

if(!is_array($data)) {

return[];

}

$ret= [

'uid'=> !isset($data['id']) ? 0 :$data['id'],

'userid'=> !isset($data['userid']) ?'':$data['userid'],

'username'=> !isset($data['username']) ?'':$data['username'],

'usericon'=> !isset($data['usericon']) ? [] :$data['usericon'],

.

.

.

//优化之前

// 'hobby' => !isset($data['hobby']) ? [] : HobbyInfo::getByIds($data['hobby']),

//优化之后

'hobby'=> !isset($data['hobby']) ? [] : self::_renderHobby($data['hobby'],$hobbyInfo),

.

.

.

if(!empty($ret['birth'])) {

$ret['zodiacSign'] = Utility::getZodiacSign($ret['birth']);

}else{

$ret['zodiacSign'] ='';

}

return$ret;

}

protectedstaticfunction_renderHobby($userHobby,$hobbyInfo)

{

$ret= [];

if($userHobby) {

$userHobbyIds=explode(',',$userHobby);

foreach($userHobbyIdsas$key=>$userHobbyId) {

$ret[$key] =$hobbyInfo[$userHobbyId];

}

}

return$ret;

}

//用户列表卡片常用字段

publicstaticfunctionrenderListCardUserinfo($data)

{

.

.

.

}

}

进一步优化

上面的代码已经优化了性能,但是还不够优雅。

获取单用户信息场景比较多,比如编辑,登录,查看单人信息等,这种情况下我还每次都提前批量查询吗?这样的话需要改造的地方太多了。

下面做进一步优化:

在render方法内部封装了一层,如果外部没有传入或传入空数组,自己再查询db获得一次需要的数据源。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

<?php

namespaceApp\Render;

.

.

.

classCommonRenderextendsBaseRender

{

publicstaticfunctionrenderUserinfo($data,$hobbyInfo= [])

{

//区别在这里:批量查询外部传入,减少sql查询次数; 单次查询在render内查一次

$hobbyInfo= !empty($hobbyInfo) ?$hobbyInfo: HobbyInfo::getAllInfo();

if(!is_array($data)) {

return[];

}

$ret= [

'uid'=> !isset($data['id']) ? 0 :$data['id'],

'userid'=> !isset($data['userid']) ?'':$data['userid'],

'username'=> !isset($data['username']) ?'':$data['username'],

'usericon'=> !isset($data['usericon']) ? [] :$data['usericon'],

.

.

.

//优化之前

// 'hobby' => !isset($data['hobby']) ? [] : HobbyInfo::getByIds($data['hobby']),

//优化之后

'hobby'=> !isset($data['hobby']) ? [] : self::_renderHobby($data['hobby'],$hobbyInfo),

.

.

.

if(!empty($ret['birth'])) {

$ret['zodiacSign'] = Utility::getZodiacSign($ret['birth']);

}else{

$ret['zodiacSign'] ='';

}

return$ret;

}

protectedstaticfunction_renderHobby($userHobby,$hobbyInfo)

{

$ret= [];

if($userHobby) {

$userHobbyIds=explode(',',$userHobby);

foreach($userHobbyIdsas$key=>$userHobbyId) {

$ret[$key] =$hobbyInfo[$userHobbyId];

}

}

return$ret;

}

//用户列表卡片常用字段

publicstaticfunctionrenderListCardUserinfo($data)

{

.

.

.

}

}

这样,那些获得单个用户资料的方法就不需要修改了。

1

2

3

4

5

6

7

8

9

10

//编辑用户资料

publicfunctioneditUserInfo(Request$request)

{

$userInfo= UserInfo::editUserById($this->_userid,$request);

return[

'user'=>

CommonRender::renderUserinfo($userInfo)

+ UserInfo::formatCoverAndPickedFootprint($userInfo)

];

}

性能对比

批量获得用户信息对比:性能提升立竿见影。

  • 比如每次取30个用户数据,之前获得爱好,职业,期望部分要查询30次db。


http://www.jsqmd.com/news/766093/

相关文章:

  • 如何精准控制固定定位头部容器中各元素的初始位置
  • 新手入门:跟快马AI学编程,手把手实现kernel32.dll修复脚本
  • 手把手拆解:一个‘非典型’SiC沟槽MOSFET如何把导通电阻砍半?(附结构图分析)
  • 【金融级容器安全合规白皮书】:Docker 27等保2.0三级适配的7大硬核落地步骤(含央行备案实操清单)
  • 空间智能技术:3D场景理解与AI性能优化
  • AI-Shoujo HF Patch:免费解锁完整游戏体验的终极解决方案
  • Clojure本地LLM集成指南:llama.clj从入门到生产部署
  • 从一次内部红队演练看Fastjson漏洞:Java安全工程师的排查与修复笔记
  • JavaScript 中按字段对嵌套对象数组进行分组的实用教程.txt
  • 鸣潮自动化终极指南:如何用ok-ww每天节省3小时游戏时间
  • GD32F103RCT6开发板GPIO实战:从点亮LED到按键检测,手把手教你玩转8种模式
  • 图片抠图怎么操作?2026年最全实操指南,一键去背景其实很简单
  • BDH-GPU:融合赫布学习与深度学习的GPU加速架构
  • 别再傻傻分不清!5分钟搞懂ROM、PROM、EPROM、EEPROM在嵌入式开发中的选型指南
  • 立足东莞,服务全球:广东洁泰以近万平基地打造超声清洗标杆 - 速递信息
  • 基于深度学习的钢材表面缺陷检测系统(YOLOv12完整代码+论文示例+多算法对比)
  • Docker网络排障实战手册(含bridge/host/overlay/macvlan/ipvlan五维对比图谱)
  • 魔兽争霸3兼容性修复终极指南:让经典游戏在现代系统完美运行
  • 企业内训系统集成AI助教时如何通过Taotoken实现成本可控与用量审计
  • 5.6闲话
  • 3分钟能做什么?用FramePack让静态照片跳起舞来!
  • Sunshine游戏串流完整教程:3步打造跨平台家庭游戏中心
  • 华为校招怎么准备:别只盯机考,真正难的是方向判断和基础深度
  • 从ClawForge看开源工具链构建:模块化设计与工程实践
  • Docker 27跨架构镜像构建必须掌握的27个底层原理:buildkit快照分层、OCI v1.1 manifest适配、binfmt_misc注册机制全解
  • 《人生底稿・番外篇12》37 岁程序员的工位双生 —— 旧主机的 “开发 + 摸鱼” 效率分区
  • 2026ISCC线上
  • 基于OpenClaw与Alpaca API的自动化交易技能实践指南
  • [20260506]建立完善ipcs.sql脚本.txt
  • DGX Spark软件优化与模型加速技术