Python中用memcached來(lái)減少數(shù)據(jù)庫(kù)查詢次數(shù)的教程
本來(lái)我一直不知道怎么來(lái)更好地優(yōu)化網(wǎng)頁(yè)的性能,然后最近做python和php同類網(wǎng)頁(yè)渲染速度比較時(shí),意外地發(fā)現(xiàn)一個(gè)很簡(jiǎn)單很白癡但是 我一直沒發(fā)現(xiàn)的好方法(不得不BS我自己):直接像某些php應(yīng)用比如Discuz論壇那樣,在生成的網(wǎng)頁(yè)中打印出“本頁(yè)面生成時(shí)間多少多少秒”,然后在 不停地訪問網(wǎng)頁(yè)測(cè)試時(shí),很直觀地就能發(fā)現(xiàn)什么操作會(huì)導(dǎo)致瓶頸,怎樣來(lái)解決瓶頸了。
于是我發(fā)現(xiàn)SimpleCD在 生成首頁(yè)時(shí),意外地竟然需要0.2秒左右,真真不能忍:對(duì)比Discuz論壇首頁(yè)平均生成才0.02秒,而Discuz論壇的首頁(yè)頁(yè)面無(wú)疑比 SimpleCD的主頁(yè)要復(fù)雜不少;這讓我情何以堪啊,因?yàn)檫@必然不是Python語(yǔ)言導(dǎo)致的差距,只能說是我完全沒做優(yōu)化而Discuz程序優(yōu)化得很好 的后果。
其實(shí)不用分析也能知道肯定是數(shù)據(jù)庫(kù)在拖累,SimpleCD在生成首頁(yè)時(shí)需要在sqlite的三個(gè)數(shù)據(jù)庫(kù)中進(jìn)行42多次查詢,是歷史原因?qū)е碌臉O其低效的一個(gè)設(shè)計(jì);但是這40多次查詢中,其實(shí)大部分是非??斓牟樵?,仔細(xì)分析一下就有兩個(gè)是性能大戶,其他都不慢。
第一個(gè)大戶就是:獲取數(shù)據(jù)個(gè)數(shù)
SELECT count(*) FROM verycd
這個(gè)操作每次都要花不少時(shí)間,這是因?yàn)槊看螖?shù)據(jù)庫(kù)都要鎖住然后遍歷一遍主鍵統(tǒng)計(jì)個(gè)數(shù)的緣故,數(shù)據(jù)量越大耗時(shí)就越大,耗時(shí)為O(N),N為數(shù)據(jù)庫(kù)大?。粚?shí)際 上解決這個(gè)問題非常容易,只要隨便在哪存一個(gè)當(dāng)前數(shù)據(jù)的個(gè)數(shù),只有在增刪數(shù)據(jù)的時(shí)候改動(dòng)就行了,這樣時(shí)間就是O(1)的了
第二個(gè)大戶就是:獲取最新更新的20個(gè)數(shù)據(jù)列表
SELECT verycdid,title,brief,updtime FROM verycd ORDER BY updtime DESC LIMIT 20;
因?yàn)樵趗pdtime上面做了索引,所以其實(shí)真正查詢時(shí)間也就是搜索索引的時(shí)間而已。然則為什么這個(gè)操作會(huì)慢呢?因?yàn)槲业臄?shù)據(jù)是按照publish time插入的,按update time進(jìn)行顯示的話就肯定需要在至少20個(gè)不同的地方做I/O,這么一來(lái)就慢了。解決的方法就是讓它在一個(gè)地方做I/O。也就是,除非數(shù)據(jù)庫(kù)加入新數(shù)據(jù) /改變?cè)袛?shù)據(jù),否則把這條語(yǔ)句的返回結(jié)果緩存起來(lái)。這么一來(lái)又快了20倍:)
接下來(lái)的是20條小case:取得發(fā)布人和點(diǎn)擊數(shù)信息
SELECT owner FROM LOCK WHERE id=XXXX; SELECT hits FROM stat WHERE id=XXXX;
這里為什么沒用sql的join語(yǔ)句來(lái)省點(diǎn)事呢?因?yàn)榧軜?gòu)原因這些數(shù)據(jù)放在不同的數(shù)據(jù)庫(kù)里,stat是點(diǎn)擊率一類的數(shù)據(jù)庫(kù),因?yàn)樾枰l繁的插入所以用 mysql存儲(chǔ);而lock和verycd是需要大量select操作的數(shù)據(jù)庫(kù),因?yàn)閙ysql悲劇的索引使用情況和分頁(yè)效率而存放在了sqlite3數(shù) 據(jù)庫(kù),所以無(wú)法join -.-
總之這也不是問題,跟剛才的解決方法一樣,統(tǒng)統(tǒng)緩存
所以縱觀我這個(gè)例子,優(yōu)化網(wǎng)頁(yè)性能可以一言以蔽之,緩存數(shù)據(jù)庫(kù)查詢,即可。我相信大部分網(wǎng)頁(yè)應(yīng)用都是這樣:)
終于輪到memcached了,既然打算緩存,用文件做緩存的話還是有磁盤I/O,不如直接緩存到內(nèi)存里面,內(nèi)存I/O可就快多了。于是memcached顧名思義就是這么個(gè)東東。
memcached是很強(qiáng)大的工具,因?yàn)樗梢灾С址植际降墓蚕韮?nèi)存緩存,大站都用它,對(duì)小站點(diǎn)來(lái)說,只要出得起內(nèi)存,這也是好東西;首頁(yè)所需要的內(nèi)存緩沖區(qū)大小估計(jì)不會(huì)超過10K,更何況我現(xiàn)在也是內(nèi)存土豪了,還在乎這個(gè)?
配置運(yùn)行:因?yàn)槭菃螜C(jī)沒啥好配的,改改內(nèi)存和端口就行了
vi /etc/memcached.conf /etc/init.d/memcached restart
在python的網(wǎng)頁(yè)應(yīng)用中使用之
import memcache mc = memcache.Client(['127.0.0.1:11211'], debug=0)
memcache其實(shí)就是一個(gè)map結(jié)構(gòu),最常使用的就是兩個(gè)函數(shù)了:
- 第一個(gè)就是set(key,value,timeout),這個(gè)很簡(jiǎn)單就是把key映射到value,timeout指的是什么時(shí)候這個(gè)映射失效
- 第二個(gè)就是get(key)函數(shù),返回key所指向的value
于是對(duì)一個(gè)正常的sql查詢可以這么干
sql = 'select count(*) from verycd' c = sqlite3.connect('verycd.db').cursor() # 原來(lái)的處理方式 c.execute(sql) count = c.fetchone()[0] # 現(xiàn)在的處理方式 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分布更均勻,其他代碼很直觀我就不解釋了。
優(yōu)化過語(yǔ)句1和語(yǔ)句2后,首頁(yè)的平均生成時(shí)間已經(jīng)降低到0.02秒,和discuz一個(gè)量級(jí)了;再經(jīng)過語(yǔ)句3的優(yōu)化,最終結(jié)果是首頁(yè)生成時(shí)間降低到了 0.006秒左右,經(jīng)過memcached寥寥幾行代碼的優(yōu)化,性能提高了3300%。終于可以挺直腰板來(lái)看Discuz了)
相關(guān)文章
Python strip lstrip rstrip使用方法
Python中的strip用于去除字符串的首位字符,同理,lstrip用于去除左邊的字符,rstrip用于去除右邊的字符。這三個(gè)函數(shù)都可傳入一個(gè)參數(shù),指定要去除的首尾字符。2008-09-09python常用時(shí)間庫(kù)time、datetime與時(shí)間格式之間的轉(zhuǎn)換教程
Python項(xiàng)目中很多時(shí)候會(huì)需要將時(shí)間在Datetime格式和TimeStamp格式之間轉(zhuǎn)化,下面這篇文章主要給大家介紹了關(guān)于python常用時(shí)間庫(kù)time、datetime與時(shí)間格式之間轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下2023-02-02python 對(duì)txt中每行內(nèi)容進(jìn)行批量替換的方法
今天小編就為大家分享一篇python 對(duì)txt中每行內(nèi)容進(jìn)行批量替換的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-07-07Django?+?Taro?前后端分離項(xiàng)目實(shí)現(xiàn)企業(yè)微信登錄功能
這篇文章主要介紹了Django?+?Taro?前后端分離項(xiàng)目實(shí)現(xiàn)企業(yè)微信登錄功能,本文記錄一下企業(yè)微信登錄的流程,結(jié)合示例代碼給大家分享實(shí)現(xiàn)思路,需要的朋友可以參考下2022-04-04實(shí)時(shí)獲取Python的print輸出流方法
今天小編就為大家分享一篇實(shí)時(shí)獲取Python的print輸出流方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2019-01-01python類:class創(chuàng)建、數(shù)據(jù)方法屬性及訪問控制詳解
下面小編就為大家?guī)?lái)一篇python類:class創(chuàng)建、數(shù)據(jù)方法屬性及訪問控制詳解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2016-07-07