把業務邏輯寫入應用程序,而不是數據庫
我們都有過這樣的經歷,從SQL數據庫中提取數據,而需要提取數據的查詢是一個復雜的查詢,有多個表連接、過濾條件和復雜的WHERE語句。像MySQL和PostgreSQL這樣的數據庫,非常擅長執行復雜的連接、過濾和排序,以便從查詢中準確獲得所需的數據。
如果在數據庫中執行這些操作,所做的實際上是將業務邏輯從應用程序里抽出,并將其移到數據庫邏輯當中。最終你會使用更多的數據庫資源和更少的應用服務器資源,來實現所期望的數據檢索結果。
在實現數據插入要求時,也是如此。在執行數據插入之前,不必驗證所插入的數據是否有效、無沖突且在應用程序中完全正確,而是讓數據庫執行驗證,將沖突標準放入數據庫模式需求中,并讓數據庫在插入的數據中拋出錯誤。
應用程序資源更容易擴展
在某些情況下,你需要數據庫做這些類型的驗證和檢查。并不是說,不要讓你的數據庫做任何應用邏輯。而是,應該讓數據庫盡可能少地做應用業務邏輯,盡可能多地在應用程序代碼本身中執行應用業務邏輯。
一般來說,擴展應用服務器資源比擴展數據庫服務器資源要容易得多。
對于大多數網絡應用程序而言,當流量增加時,通常可以輕松地增加應用服務器,來處理增加的負載。但是,除非數據庫也能擴展到處理增加的負載,否則額外的應用服務器并沒有什么幫助。
觀察應用程序的可用資源。您應該將數據庫看作是由稀缺的計算資源組成的,而應用程序代碼層(包括服務)是由隨時可用的計算資源組成的,這些計算資源可以很容易地擴展。
數據庫資源是稀缺的,計算資源隨時可用。
一旦你能理解這種思維方式,你就會意識到在應用程序層中,放置盡可能多的邏輯,將有助于更容易地擴展。而將業務邏輯放在數據庫層會極大地限制該業務邏輯的可伸縮性。
讓數據庫處理復雜的過濾問題
不可能總是把所有的業務邏輯放在應用層。有時,你必須把某些查詢放在數據庫里。這樣做的一個有效原因,可能是為了控制返回結果的數量。假設一個查詢在一個非常大的數據庫表上有一個復雜的過濾條件:

在大型數據集上,執行復雜的過濾查詢后,預期的結果可能只有表中的幾條記錄。*將從這幾行返回所有數據。但是,如果希望在應用層,而不是數據庫中,執行復雜的過濾查詢,則通常需要先從數據庫中檢索所有的數據。你最終可能會出現這樣的結果:

這將把mytable中所有數據返回給應用層。然后,應用層將扔掉任何沒有通過它在數據上執行的過濾條件的行。這樣做的問題是,為了執行這個需求,mytable的全部內容都必須被轉移到應用層。對于大型數據集來說,這是不可接受的。
在許多情況下,簡單地重構一個查詢或一系列查詢,可以避免此類問題,并允許你在應用程序中執行更多的邏輯,而不會產生不必要的數據流量。做到這一點的一個方法是將數據過濾與數據檢索分離開來。
過濾與檢索分離
我們經常把過濾結果和檢索結果的概念合并到單個查詢中。特別是當我們查看有很多數據的大表時,編寫一個查詢,執行所有的過濾和規范,選擇我們需要的行,然后讓查詢從選擇的行中,返回需要的所有數據,這是非常方便的。

就其本身而言,這似乎沒什么問題。但是,當查詢涉及到復雜的連接或其他復雜的操作時,它就會給數據庫帶來不小的負荷,使數據庫資源緊張。
解決這個問題的方法是執行一個初始查詢,只簡單地從所有行中返回過濾查詢所需的字段,然后在應用程序中執行過濾邏輯。讓我們假設field1和field2是上述<復雜的過濾查詢>中實際涉及的字段。所以,讓我們在初始查詢中只獲得這些數據:

然后,我們可以在你的應用程序代碼中對field1和field2執行復雜過濾器查詢邏輯。這將導致我的表格中符合復雜查詢的行的ID列表。一旦你有了匹配的ID列表,你就可以執行后續的查詢,從預過濾的行中獲取實際數據:

這兩個查詢都是非常簡單的查詢,不需要在數據庫中進行復雜的操作。選擇返回數據的必要業務邏輯是在應用層執行的,但需要從數據庫傳輸到應用的無關數據很少。通過將查詢分割成獨立的過濾和數據檢索查詢,你已經重構了你的請求,并允許復雜的、資源密集的業務邏輯在應用程序中執行,而不是數據庫。
避免對返回的結果進行操作
將業務邏輯從數據庫移到應用程序層的另一種簡單方法是避免對數據庫中返回的結果執行計算;而是在應用程序中執行它們。因此,不要做這樣的事情。

你可以這樣做:

然后,在應用程序中對返回的結果執行POWER(SQRT(field1)*SIN(field2),5)的等效計算。其結果是,執行計算所需的所有計算都利用了現成的應用程序資源,而不是稀缺的數據庫資源。
將連接轉移到應用層
復雜的連接是需要大量數據庫資源。與其在數據庫中連接數據,不如將盡可能多地連接邏輯轉移到應用層中。以這種方式重構代碼,可以顯著減少數據庫的負載,同時提高可伸縮性。
當然,不可能總是以這些方式重構查詢。有時,只需要在數據庫本身中執行一個復雜的查詢。但是,通過盡可能多地刪除這些復雜的查詢,你可以減少對稀缺的數據庫資源的依賴,增加對高可用的應用級資源的依賴。
因此,下次當你看到使用多個連接和復雜過濾邏輯的大型、長且復雜的查詢時,不要為此感到困難。相反,考慮用更簡單的查詢(可能是多個查詢)和在應用程序層中執行的業務邏輯替換它的方法。
隨著應用程序的擴展,你會感受到改進的靈活性。