在 Laravel 項目中,隨著流量增長,數據庫查詢速度變慢的情況並不少見。最近在優化一個房地產平台的後端時,我遇到了這個問題,並從中吸取了一些經驗教訓。
數據庫優化是開發可擴展、高性能應用程序的關鍵領域之一。它能提升數據檢索速度,從而縮短響應時間和頁面加載時間,並降低服務器負載,最大限度地降低成本。
想像一下:你構建了一個出色的房地產平台,服務於多個城市,並配備了高級搜索過濾器。房產列表加載速度很快,搜索過濾器響應迅速,一切看起來都很完美。但是,隨著應用程序規模的擴大和用戶群的增長,那些在開發過程中表現完美的查詢開始執行時間越來越長。是不是聽起來很熟悉?
這正是我們平台遇到的情況。 Sentry 警報在生產環境中標記了緩慢的數據庫查詢,這給了我們一個警醒。監控顯示,搜索結果查詢需要 5 秒以上才能完成——這與我們承諾的快速體驗相差甚遠!
還記得那些玩遊戲時,擊敗一個敵人會產生多個較小敵人的情況嗎?這與 Laravel 中的 N 1 查詢問題本質上是一樣的。你獲取房產列表,然後為每個房產進行額外的查詢以獲取相關數據。在你意識到之前,你的數據庫正在處理數百個查詢,而不是只有一個。
以下是它的典型表現:
<code>// 优化前 $properties = Property::all(); foreach ($properties as $property) { echo $property->agent->name; // 每个房产都会触发一个新的查询 } // 优化后 // 使用 `with()` 进行预加载 $properties = Property::with(['agent'])->get(); foreach ($properties as $property) { echo $property->agent->name; // 不需要额外的查询! }</code>
可以將數據庫索引比作書的索引——它們可以幫助你找到所需內容,而無需掃描每一頁。但是,索引遠不止將索引添加到每一列。讓我們深入探討。
<code>// 基本的单列索引 Schema::table('properties', function (Blueprint $table) { $table->index('price'); }); // 多列的组合索引 Schema::table('properties', function (Blueprint $table) { $table->index(['city', 'price']); // 顺序很重要! }); // 唯一索引 Schema::table('properties', function (Blueprint $table) { $table->unique('property_code'); });</code>
<code> // 良好:匹配查询模式 $properties = Property::where('city', 'New York') ->whereBetween('price', [200000, 500000]) ->get(); // 索引应匹配此模式 $table->index(['city', 'price']); // 首先是城市,然后是价格</code>
選擇性索引 並非每一列都需要索引。選擇要索引哪些列的一些指導原則包括:
監控索引使用情況
<code> -- 检查索引使用情况的 MySQL 查询 SELECT table_name, index_name, index_type, stat_name, stat_value FROM mysql.index_statistics WHERE table_name = 'properties';</code>
我見過的(以及犯過的)最常見的錯誤之一是默認使用 select *。這就像去雜貨店購物,卻買下整個商店的東西,而你只需要一頓飯的食材。以下是一種更好的方法:
<code>// 优化前 $properties = Property::all(); foreach ($properties as $property) { echo $property->agent->name; // 每个房产都会触发一个新的查询 } // 优化后 // 使用 `with()` 进行预加载 $properties = Property::with(['agent'])->get(); foreach ($properties as $property) { echo $property->agent->name; // 不需要额外的查询! }</code>
處理大型數據集時,在單個操作中處理所有內容可能會壓垮系統的資源並造成瓶頸。相反,可以使用 Laravel 的 chunk 方法以可管理的批次處理記錄:
<code>// 基本的单列索引 Schema::table('properties', function (Blueprint $table) { $table->index('price'); }); // 多列的组合索引 Schema::table('properties', function (Blueprint $table) { $table->index(['city', 'price']); // 顺序很重要! }); // 唯一索引 Schema::table('properties', function (Blueprint $table) { $table->unique('property_code'); });</code>
緩存就像有一個能夠記住一切的好助手。但是,像任何助手一樣,它需要明確的指示。
<code> // 良好:匹配查询模式 $properties = Property::where('city', 'New York') ->whereBetween('price', [200000, 500000]) ->get(); // 索引应匹配此模式 $table->index(['city', 'price']); // 首先是城市,然后是价格</code>
專業提示:不要緩存所有內容!重點關注:
數據庫優化不是一項可以從清單中勾選的一次性任務。它更像是照料花園——定期維護和關注才能獲得最佳效果。從這些基礎知識開始,監控應用程序的性能,並不斷改進你的方法。
記住,目標不是實現你所知道的每種優化技術。而是要在代碼可維護性和性能之間找到適合你特定用例的平衡點。有時,一個簡單的預加載語句比花費數小時進行複雜的優化策略對應用程序的性能更有幫助。
你在 Laravel 項目中遇到了哪些優化挑戰和/或解決了哪些問題?讓我們在評論中討論!
以上是Laravel績效調整:優化數據庫查詢以進行可伸縮性的詳細內容。更多資訊請關注PHP中文網其他相關文章!