我有一個php,每天計劃任務執行一次,邏輯如下:
1.連接資料庫,從資料庫中Select讀取相關資料到數組
2.根據得到的資料數量進行循環,循環中間包含3個mysql操作( select、insert、update各一個)
3.循環完後關閉資料庫連線
循環執行的次數是根據步驟1的mysql_num_rows而定,基本上幾千上萬。
那麼在循環過程中就會短時間內連續執行幾千上萬X3次資料庫操作,效率非常低。且因為循環次數多任務重需要很長時間才能執行完,會導致nginx出現504錯誤。
且頻繁資料庫操作和長連接,佔用過多資源,導致整個環境效率低下。
請問該怎麼優化呢?
麻煩各位大神賜教,先謝謝了
回覆內容:
我有一個php,每天計劃任務執行一次,邏輯如下:
1.連接資料庫,從資料庫中Select讀取相關資料到數組
2.根據得到的資料數量進行循環,循環中間包含3個mysql操作( select、insert、update各一個)
3.循環完後關閉資料庫連線
循環執行的次數是根據步驟1的mysql_num_rows而定,基本上幾千上萬。
那麼在循環過程中就會短時間內連續執行幾千上萬X3次資料庫操作,效率非常低。且因為循環次數多任務重需要很長時間才能執行完,會導致nginx出現504錯誤。
且頻繁資料庫操作和長連接,佔用過多資源,導致整個環境效率低下。
請問該怎麼優化呢?
麻煩各位大神賜教,先謝謝了
就你說的這個情況,建議不要用請求的方式解決,用crontab 加計劃任務在後台運行php 腳本,資料庫查詢時分批處理,比如總共100000 條,每次1000 條;如果必須逐條處理且速度不會很快,建議一邊fetch_row 一邊處理,避免先放入array 再循環。記得根據執行情況 set_time_limit 和資料庫連線的逾時時間。
關於這種資料量稍大的長時任務說幾點我的看法:
1、web環境下不適合長時任務:nginx+php-fpm這種架構是不適合執行長時任務的,中間的各種超時能折磨死人,Apache+PHP要好一些起碼好控制超時,簡單一個set_time_limit(0)就能搞定。
2、任務調度透過web來實現:大多數PHP框架對命令列支援並不好,或者說實現的時候並沒有考慮對命令列的支持,所以一個基於web任務分發機制會容易實現一些,這樣對現有框架的侵入性也會小很多,而且一個穩定的項目,保證入口的統一是極其重要的。如果任務在命令列下運行的話需要考慮很多問題,最突出的問題就是文件權限問題,一般web項目都是用apache之類的用戶運行的,所產生的文件所有者也是apache,而且apache普遍是不允許登陸的,雖然可以實作用apache使用者執行指令,但比較複雜。
3、分而治之:處理長時任務的一個解決方案就是分治,將大任務拆分為小任務,將長時任務轉換為多個短時的小任務,降低對資源的佔用時間,減少因為長時間執行而導致的各種問題,如資料庫連線逾時,PHP記憶體外洩等問題。
附上我寫的一個例子請多多指教
https://github.com/zkc226/cur...
大量資料的時候交由任務系統去執行。首先發起一個請求,由訊息生產者將請求交給消費者處理,並返回,避免等待出現逾時。消費者執行多線程處理。建議使用Gearman,使用起來很方便,而且支援PHP介面。其它的類似Workman,Swoole等都能實現。
所有的操作都集中在同一台伺服器上的同一個時間點執行, 肯定是耗時又耗資源的.
要么像@黃弘說的,分批處理.
要么就增加服務器, 把這些任務分散到其他的伺服器上執行, 所謂分散式處理, 但是又會增加任務的複雜度, 因為還要保證資料的一致性
1.匯出資料到文件,讀文件去循環。 (如mysqldump)
2.考慮是否可以先拼語句,批次執行。而不是每個循環都執行。
3.考慮是否可以用預存程序
並且因為循環次數多任務重需要很長時間才能執行完,會導致nginx出現504錯誤。
是即時計算?計算量大的任務是否考慮後台跑任務計算好寫入緩存,即時請求只讀快取。
這個問題有一點像我之前回答的那個並行執行提高效率的問題
本質就是針對讀取這個大數據進行分流,按ID進行取模並行執行,例如你的伺服器和資料庫能承受20個並發執行
那並行最簡單的方式就是開20個腳本進程執行
0.php -> select * from test where id%20=0;
1.php -> select * from test where id%20=1;
2 .php -> select * from test where id%20=2;
....
這個是拉的方式。
還有一種方式是推到隊列,隊列再調用woker進程去執行,這樣更規範化好管理,比如樓上有一個提到的gearman,我之前在做短信平台的時候也有每日定時任務,就是用的這個。
邏輯大概是你開一個定時任務腳本把所有查詢出來的資料透過呼叫gearman客戶端把資料任務發到gearman調度器,然後你開20個woker(可以在同一台伺服器也可以在區域網路內的不同伺服器),然後調度器就會被分配到這20個gearman woker腳本去執行,每個worker腳本代碼一樣,是一條數據一個任務的執行
用cli模式的PHP腳本處理即可,不要使用WEB方式,很容易超時

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

方法:1、用“str_replace(" ","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\ \;||\xc2\xa0)/","其他字符",$str)”语句。

查找方法:1、用strpos(),语法“strpos("字符串值","查找子串")+1”;2、用stripos(),语法“strpos("字符串值","查找子串")+1”。因为字符串是从0开始计数的,因此两个函数获取的位置需要进行加1处理。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)