1

所以我使用mini-profiler,它給了我很好的數據。如何優化我的HTML而不是SQL查詢的呈現?

但是,我注意到的一件事是,我已經將很多SQL調用降到最低,現在最重要的是渲染各種偏分量和HTML。

舉例來說,這裏是我現在面臨的問題,2個不同的例子:

迷你探查

GET http://localhost:3000/ 14.0 +0.0 
    Executing action: index 9.5 +9.0 
    Rendering: home/index  7.8 +16.0 
    Rendering: home/_row  7.9 +22.0 
    Rendering: layouts/application 1038.7 +32.0 
    Rendering: layouts/_navigation 6.0 +586.0 

Development.log

Started GET "/" for 127.0.0.1 at 2013-05-17 18:00:26 -0500 
Processing by HomeController#index as HTML 
    Item Load (0.6ms) SELECT "items".* FROM "items" WHERE "items"."is_approved" = 't' 
    ActsAsTaggableOn::Tag Load (0.6ms) SELECT "tags".* FROM "tags" INNER JOIN "taggings" ON "tags"."id" = "taggings"."tag_id" WHERE "taggings"."taggable_id" = 13 AND "taggings"."taggable_type" = 'Item' AND (taggings.context = 'tags' AND taggings.tagger_id IS NULL) 
    Rendered home/_row.html.erb (8.0ms) 
    Rendered home/index.html.erb within layouts/application (15.7ms) 
    Rendered layouts/_social_media.html.erb (0.5ms) 
    (0.4ms) SELECT items.id FROM "items" 
    ActsAsTaggableOn::Tag Load (0.7ms) SELECT tags.*, taggings.tags_count AS count FROM "tags" JOIN (SELECT taggings.tag_id, COUNT(taggings.tag_id) AS tags_count FROM "taggings" INNER JOIN items ON items.id = taggings.taggable_id WHERE (taggings.taggable_type = 'Item' AND taggings.context = 'tags') AND (taggings.taggable_id IN(13)) GROUP BY taggings.tag_id HAVING COUNT(taggings.tag_id) > 0) AS taggings ON taggings.tag_id = tags.id ORDER BY count LIMIT 5 
    Rendered layouts/_navigation.html.erb (6.1ms) 
    Rendered layouts/_site_nav.html.erb (0.6ms) 
    Rendered layouts/_messages.html.erb (0.2ms) 
    Rendered layouts/_footer.html.erb (0.1ms) 
Completed 200 OK in 1069ms (Views: 1066.0ms | ActiveRecord: 2.3ms) 

從迷你的輸出-Profiler在頂部,顯示主要application.html.erb正在添加顯着一定要加載時間。

這裏是另一個應用程序的另一個例子,其中的觀點是最耗時的那些渲染:

Started GET "/" for 127.0.0.1 at 2013-05-17 17:55:01 -0500 
    User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1 
Processing by HomeController#index as HTML 
    Category Load (0.2ms) SELECT "categories".* FROM "categories" LIMIT 6 
    Banner Load (0.2ms) SELECT "banners".* FROM "banners" INNER JOIN "banner_types" ON "banner_types"."id" = "banners"."banner_type_id" WHERE (banner_types.name = 'Featured') 
    Banner Load (0.2ms) SELECT "banners".* FROM "banners" INNER JOIN "banner_types" ON "banner_types"."id" = "banners"."banner_type_id" WHERE (banner_types.name = 'Side') 
    Product Load (0.3ms) SELECT "products".* FROM "products" 
    Vendor Load (0.3ms) SELECT "vendors".* FROM "vendors" WHERE "vendors"."id" IN (12, 11, 10) 
    Vendor Load (0.2ms) SELECT "vendors".* FROM "vendors" 
    User Load (0.2ms) SELECT "users".* FROM "users" 
    Rendered home/_popular_products.html.erb (16.1ms) 
    Rendered home/_popular_stores.html.erb (2.4ms) 
    Rendered home/index.html.erb within layouts/application (26.4ms) 
    Piggybak::Sellable Load (0.2ms) SELECT "sellables".* FROM "sellables" WHERE "sellables"."id" = 1 LIMIT 1 
    Rendered layouts/_login_nav.html.erb (8.2ms) 
    Rendered layouts/_navigation.html.erb (0.8ms) 
    CACHE (0.0ms) SELECT "vendors".* FROM "vendors" 
    Rendered layouts/_store_dropdown.html.erb (2.2ms) 
    Rendered layouts/_header.html.erb (18.1ms) 
    Rendered layouts/_messages.html.erb (0.3ms) 
    Rendered layouts/_footer.html.erb (0.9ms) 
Completed 200 OK in 242ms (Views: 209.8ms | ActiveRecord: 1.9ms) 

當然,這個特殊的時間正好是209.8ms,但它已經高達5,000ms在各種加載時間。

如何優化這些視圖&偏差的渲染?或者我可以使用什麼工具來至少弄清楚是什麼導致了長時間的加載時間,這樣我就可以慢慢地把它弄碎了?

回答

0

在你的第二個例子,我看到查詢:

  • 類型的所有橫幅 「精選」
  • 型 「邊」 的所有橫幅
  • 所有產品
  • 全部供應商
  • 所有用戶

如果你的諧音必須通過對象的巨大集合迭代,它會渲染時間大大放緩。

監視用於調用集合的迭代器,如Vendor.all.each do |v|。不應該在視圖中調用模型類方法。在你需要的對象的控制器中構建一個集合,然後通過實例變量發送到視圖。

+0

我通常這麼做......但在這種情況下,我需要渲染集合中出現在佈局中的部分。我在哪個控制器中渲染? 'application_controller'?它是整個網站導航的一部分 - 或多或少。 – marcamillion

+0

全局佈局中的數據庫支持內容不完全是基於性能的設計。在頁面加載後,我會將其解壓縮到ajax請求。例如,使用ajax以用戶ID擊中消息控制器,該控制器將適當地確定範圍並返回與用戶相關的消息。 – Substantial

+0

我知道這不是基於性能的設計,但它是基於商業規則的設計。我需要從系統中所有供應商的集合中生成一個'ul'。不能把它放在控制器中 - 無論我如何進行調用,即ajax或Vendor.all.each,它們有什麼不同?它仍然會爲每個頁面加載呼叫。 – marcamillion

1

你正在開發這個簡介。請注意,由於config.cache_classes設置,您的應用程序會在該環境中的每個請求中重新加載。將該設置設置爲true進行分析可能會給您不同的結果(通常更快)。

在其中一條評論中,您提到了Vendor.all.each片段。我會檢查實際需要多長時間。只需將其包裝在results = Benchmark.measure do區塊中,並查看results.real爲您提供了什麼。假設它在50毫秒內完成。

你有三個選擇,一般爲:

  • 如果50ms的不理想,閱讀您在一定的時間間隔再生一個靜態文件的部分呈現結果。這可以通過使用rails緩存機制或將其放入一個使用cronjob重新生成的文件來完成。無論哪種方式,對於可能在間隔之間創建的新供應商而言,這都會造成某種延遲。或者,如果50ms適合你,你可以將它們轉換爲JSON(速度很快,看看https://github.com/ohler55/oj),並且如前所述,使用AJAX將其拉下,並使用javascript呈現html。這具有HTML的實際呈現在瀏覽器內完成的優點。瀏覽器運行速度更快,而且通常負載較少以應對。

  • 如果您對50毫秒感到不滿,並且無法忍受頁面上過時的信息,您將不得不開始使用選項2,但不使用ActiveRecord,直接使用mysql ruby​​適配器。或者您確保無論何時創建新的供應商或更新舊的供應商,都可以將JSON添加到相應供應商的文本列中,可能會使用一些after_validation回調。所以你至少可以做

    vendors = Vendor.select(:json_cache).map{|v| v.json_cache}.join(',') 
    vendors = "[#{vendors}]" 
    render :json => vendors 
    

    ...不完全美麗,但快速燃燒。

我希望這是你想知道的。