Python中用memcached来减少数据库查询次数的教程


Posted in Python onApril 07, 2015

本来我一直不知道怎么来更好地优化网页的性能,然后最近做python和php同类网页渲染速度比较时,意外地发现一个很简单很白痴但是 我一直没发现的好方法(不得不BS我自己):直接像某些php应用比如Discuz论坛那样,在生成的网页中打印出“本页面生成时间多少多少秒”,然后在 不停地访问网页测试时,很直观地就能发现什么操作会导致瓶颈,怎样来解决瓶颈了。

于是我发现SimpleCD在 生成首页时,意外地竟然需要0.2秒左右,真真不能忍:对比Discuz论坛首页平均生成才0.02秒,而Discuz论坛的首页页面无疑比 SimpleCD的主页要复杂不少;这让我情何以堪啊,因为这必然不是Python语言导致的差距,只能说是我完全没做优化而Discuz程序优化得很好 的后果。

其实不用分析也能知道肯定是数据库在拖累,SimpleCD在生成首页时需要在sqlite的三个数据库中进行42多次查询,是历史原因导致的极其低效的一个设计;但是这40多次查询中,其实大部分是非常快的查询,仔细分析一下就有两个是性能大户,其他都不慢。

第一个大户就是:获取数据个数
 

SELECT count(*) FROM verycd

这个操作每次都要花不少时间,这是因为每次数据库都要锁住然后遍历一遍主键统计个数的缘故,数据量越大耗时就越大,耗时为O(N),N为数据库大小;实际 上解决这个问题非常容易,只要随便在哪存一个当前数据的个数,只有在增删数据的时候改动就行了,这样时间就是O(1)的了

第二个大户就是:获取最新更新的20个数据列表
 

SELECT verycdid,title,brief,updtime FROM verycd
 
  ORDER BY updtime DESC LIMIT 20;

因为在updtime上面做了索引,所以其实真正查询时间也就是搜索索引的时间而已。然则为什么这个操作会慢呢?因为我的数据是按照publish time插入的,按update time进行显示的话就肯定需要在至少20个不同的地方做I/O,这么一来就慢了。解决的方法就是让它在一个地方做I/O。也就是,除非数据库加入新数据 /改变原有数据,否则把这条语句的返回结果缓存起来。这么一来又快了20倍:)

接下来的是20条小case:取得发布人和点击数信息
 

SELECT owner FROM LOCK WHERE id=XXXX;
 
SELECT hits FROM stat WHERE id=XXXX;

这里为什么没用sql的join语句来省点事呢?因为架构原因这些数据放在不同的数据库里,stat是点击率一类的数据库,因为需要频繁的插入所以用 mysql存储;而lock和verycd是需要大量select操作的数据库,因为mysql悲剧的索引使用情况和分页效率而存放在了sqlite3数 据库,所以无法join -.-

总之这也不是问题,跟刚才的解决方法一样,统统缓存

所以纵观我这个例子,优化网页性能可以一言以蔽之,缓存数据库查询,即可。我相信大部分网页应用都是这样:)

终于轮到memcached了,既然打算缓存,用文件做缓存的话还是有磁盘I/O,不如直接缓存到内存里面,内存I/O可就快多了。于是memcached顾名思义就是这么个东东。

memcached是很强大的工具,因为它可以支持分布式的共享内存缓存,大站都用它,对小站点来说,只要出得起内存,这也是好东西;首页所需要的内存缓冲区大小估计不会超过10K,更何况我现在也是内存土豪了,还在乎这个?

配置运行:因为是单机没啥好配的,改改内存和端口就行了
 

vi /etc/memcached.conf
 
/etc/init.d/memcached restart

在python的网页应用中使用之
 

import memcache
 
mc = memcache.Client(['127.0.0.1:11211'], debug=0)

memcache其实就是一个map结构,最常使用的就是两个函数了:

  1.     第一个就是set(key,value,timeout),这个很简单就是把key映射到value,timeout指的是什么时候这个映射失效
  2.     第二个就是get(key)函数,返回key所指向的value

于是对一个正常的sql查询可以这么干

sql = 'select count(*) from verycd'
 
c = sqlite3.connect('verycd.db').cursor()
 
 
 
# 原来的处理方式
 
c.execute(sql)
 
count = c.fetchone()[0]
 
 
 
# 现在的处理方式
 
from hashlib import md5
 
key=md5(sql)
 
count = mc.get(key)
 
if not count:
 
  c.execute(sql)
 
  count = c.fetchone()[0]
 
  mc.set(key,count,60*5) #存5分钟

 

其中md5是为了让key分布更均匀,其他代码很直观我就不解释了。

优化过语句1和语句2后,首页的平均生成时间已经降低到0.02秒,和discuz一个量级了;再经过语句3的优化,最终结果是首页生成时间降低到了 0.006秒左右,经过memcached寥寥几行代码的优化,性能提高了3300%。终于可以挺直腰板来看Discuz了)

Python 相关文章推荐
Python实现根据指定端口探测服务器/模块部署的方法
Aug 25 Python
编写Python脚本使得web页面上的代码高亮显示
Apr 24 Python
基于Python实现文件大小输出
Jan 11 Python
Python中常用操作字符串的函数与方法总结
Feb 04 Python
Python3实现的字典遍历操作详解
Apr 18 Python
Django添加KindEditor富文本编辑器的使用
Oct 24 Python
Python将string转换到float的实例方法
Jul 29 Python
python获取Pandas列名的几种方法
Aug 07 Python
python利用opencv实现SIFT特征提取与匹配
Mar 05 Python
python学生管理系统的实现
Apr 05 Python
Django框架实现在线考试系统的示例代码
Nov 30 Python
详解java调用python的几种用法(看这篇就够了)
Dec 10 Python
Python3中常用的处理时间和实现定时任务的方法的介绍
Apr 07 #Python
Python中使用pprint函数进行格式化输出的教程
Apr 07 #Python
利用QT写一个极简单的图形化Python闹钟程序
Apr 07 #Python
分析Python编程时利用wxPython来支持多线程的方法
Apr 07 #Python
Python中尝试多线程编程的一个简明例子
Apr 07 #Python
Python的Flask框架中Flask-Admin库的简单入门指引
Apr 07 #Python
用Python实现一个简单的线程池
Apr 07 #Python
You might like
使用PHP把HTML生成PDF文件的几个开源项目介绍
2014/11/17 PHP
Aster vs KG BO3 第三场2.19
2021/03/10 DOTA
javascript flash下fromCharCode和charCodeAt方法使用说明
2008/01/12 Javascript
Riot.js 快速的JavaScript单元测试框架
2009/11/09 Javascript
dojo学习第二天 ajax异步请求之绑定列表
2011/08/29 Javascript
javascript仿php的print_r函数输出json数据
2013/09/13 Javascript
jQuery中ajax和post处理json的不同示例对比
2014/11/02 Javascript
详解JavaScript基于面向对象之创建对象(1)
2015/12/10 Javascript
js手机号批量滚动抽奖实现代码
2020/04/17 Javascript
微信小程序 基础组件与导航组件详细介绍
2017/02/21 Javascript
微信小程序页面开发注意事项整理
2017/05/18 Javascript
vue父子组件的嵌套的示例代码
2017/09/08 Javascript
详解利用 Express 托管静态文件的方法
2017/09/18 Javascript
javaScript 连接打印机,打印小票的实例
2017/12/29 Javascript
详解小程序如何避免多次点击,重复触发事件
2019/04/08 Javascript
nodejs中实现用户注册路由功能
2019/05/20 NodeJs
layui表单提交到后台自动封装到实体类的方法
2019/09/12 Javascript
[00:10]DOTA2 TI9勇士令状明日上线
2019/05/07 DOTA
Python3使用requests登录人人影视网站的方法
2016/05/11 Python
Python编写登陆接口的方法
2017/07/10 Python
Python正则捕获操作示例
2017/08/19 Python
python爬虫系列Selenium定向爬取虎扑篮球图片详解
2017/11/15 Python
Django框架多表查询实例分析
2018/07/04 Python
Windows10下 python3.7 安装 facenet的教程
2019/09/10 Python
python模块常用用法实例详解
2019/10/17 Python
python怎么判断模块安装完成
2020/06/19 Python
高性能钓鱼服装:Huk Gear
2019/02/20 全球购物
美国摩托车头盔、零件、齿轮及配件商店:Cycle Gear
2019/06/12 全球购物
餐饮企业总经理岗位职责范文
2014/02/18 职场文书
乡镇党员群众路线教育实践活动对照检查材料思想汇报
2014/10/05 职场文书
社区党风廉政建设调研报告
2015/01/01 职场文书
成本会计岗位职责
2015/02/03 职场文书
获奖感言怎么写
2015/07/31 职场文书
高中化学教学反思
2016/02/22 职场文书
Python使用psutil库对系统数据进行采集监控的方法
2021/08/23 Python
win10如何快速切换窗口 win10切换窗口快捷键分享
2022/07/23 数码科技