數據庫可以承受很高的查詢頻率,但是對一個表過於頻繁的查詢,或者索引建立的不好,使得查詢和占用過程太久,非常容易鎖表,另外一些嚴重的是:對表統計,按沒有索引的字段查詢,分組匯總,對字段作函數(function(col_name))而造成不走索引,或者索引無法覆蓋條件,或者對一個表作大量刪除,插入,造成索引更新。如此種種,對客戶端數量眾多的使用系統,最直接的結果就是鎖表,或者返回慢。服務器端反映就是慢,或者CPU,RAM占用滿。一些OA,工單運用將刷新時間設置的太短,客戶端少時,問題不明顯,客戶端多的時候,整個系統反映遲鈍。甚至鎖死。
我整理了一些想法。但自己並不專業,有錯誤肯提。
1. 本地需要的一些常用資源,必須在啟動時,或者第一次用到時檢索到本地,直到關閉客戶端時,就只會檢索服務器一次。比如部門,或者一些下拉選擇項,這些開帳後不容易變動,如果某客戶端申請增加了一個選項,比如"收費項目",提醒她退出一次即可。
2. 不容易變動的,而且是頻繁使用的應該先到本地來。在本地有兩個數據表,需要一個數據時,比如單據時間,要看本地有沒有,沒有再寫內嵌式SQL去查詢,不要動不動就是內嵌式SQL。
3. 避免在本地構建復雜的SQL語句,復雜SQL考慮在存儲器裡作。因為簡單select語句構建的過程執行無法分步進行(或者語句看起來零亂無序),整個返回之前,可能需要鎖住的資源比較多。用procedure主要是代碼經過編譯和優化,而一般的查詢語句,如果比較復雜,我們的經驗知道返回都很慢,而你重復的查詢一次,就比較快了。如果100個客戶端都要這麼一個過程的話,對服務器是個拖累。而且層次不清和維護很難。更新也沒存儲器方便。
4. 在存儲器中。如果對一張用戶使用很頻繁的表(主要信息表)作匯總,或者大面積返回時,會有困難。為了避免這個問題,存儲器要把需要的字段提前檢索出來,到一個臨時表裡,再操作,不會干擾到其他人的使用。因為有的人會用分類匯總,排序,以及用沒有索引的字段參與篩選,或者對字段作函數運算,都是非常耗時的。有的要使用光標fetch。另外要重復使用一個數據時,比如根據字段:status來作一些不同的統計,要先檢索到一個變量裡,避免頻繁的無謂的重復查表。
5. 在master-detail的表現形式時,有的用戶會在master表頻繁的點擊。注意用戶如果點擊時沒換行,不需要重新檢索。我之前很好笑,一直沒注意到這個問題。查詢的頻率會高十倍以上。(好笑)
6. 有時我們的程序在tab_control或者跌層或者展示部分隱藏時,用戶實際上看不到隱藏的部分,所以也不需要刷新數據。節省這些地方能省下很多檢索。
7. 自動刷新的界面要概算一個適合的時間間歇。如果一個系統10個人,10秒刷一下都沒問題。但是一個系統50,100個人在用,刷新實際上是災難的。對一些FK表到沒問題,對有人頻繁寫入數據的表就不行。比如要統計每個部門新的工單數量,可以定時由存儲器統一把結果刷到一個另外的表裡,然後其他人從另外的那個表裡讀取,不需要每個人都來調用刷新的SQL語句來作分組count或者sum。比如服務器作就是一分鐘時間一次,而客戶端來作就是一分鐘100次。
8. 開啟一個測試客戶端,仔細跟蹤提交的語句,逐漸優化和分析。減少不必要的查詢。
9. 三層結構因為會話獨立,所以並不能改善以上問題。因為只是商業邏輯得到集中存放和調用。本身的檢索還是要注意優化。比如上面說的部門代號表,雖然通過三層去讀取,但也要一次都到本地來。而不是反復讀。
10. 不要試圖構建復雜的觸發器。是個大忌。
11. 客戶端數據返回行數的限制,默認的情況下,你可以限制為select top 100 * from table而界面可以給一個勾選項,如果客戶要返回更多,去掉勾即可。我看一些web程序,每頁只有20行,如果一些全局管理職位,她通常要一次導出所有的數據來,或者她看到范圍比較大,幾乎被系統累死掉。所以通常情況下,考慮一般操作人員作最優性限制,而對一些特殊用戶,要放寬限制。
12. 列數和行數一樣,返回太多速度很慢,只需要必要的欄位。但有時為了一個部件通用,而不會去節省一些列的返回也是可以的。
13. 查詢時,不要自作多情的先給出一個list。我見過一個Delphi程序員,他作的BOM表查詢一進去界面就列出200行數據的一個列表,我覺得是不必要的。用戶按條件查詢就可以了。不外乎在條件組合靈活一些,或者緩存歷史記錄,或者給一些便捷的按鈕即可。BOM表的物料那麼多,即使你給一個列表,要在列表裡查找也是個問題。這是個低概率問題。比如說故障工單處理,客戶一進去倒可以刷新出最近50張,因為用戶會察看這些單,是個高概率問題,這個是可以的。