日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
加速RubyonRails消除N+1查詢問(wèn)題

Ruby語(yǔ)言常以其靈活性為人所稱道。正如Dick Sites所言,您可以 “為了編程而編程”。Ruby on Rails擴(kuò)展了核心Ruby 語(yǔ)言,但正是 Ruby 本身使得這種擴(kuò)展成為了可能。

我們注重客戶提出的每個(gè)要求,我們充分考慮每一個(gè)細(xì)節(jié),我們積極的做好成都網(wǎng)站設(shè)計(jì)、成都網(wǎng)站制作服務(wù),我們努力開(kāi)拓更好的視野,通過(guò)不懈的努力,成都創(chuàng)新互聯(lián)贏得了業(yè)內(nèi)的良好聲譽(yù),這一切,也不斷的激勵(lì)著我們更好的服務(wù)客戶。 主要業(yè)務(wù):網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)站設(shè)計(jì),小程序設(shè)計(jì),網(wǎng)站開(kāi)發(fā),技術(shù)開(kāi)發(fā)實(shí)力,DIV+CSS,PHP及ASP,ASP.Net,SQL數(shù)據(jù)庫(kù)的技術(shù)開(kāi)發(fā)工程師。

Ruby on Rails使用了該語(yǔ)言的靈活性,這樣一來(lái),無(wú)需太多樣板或額外的代碼就可以輕松編寫(xiě)高度結(jié)構(gòu)化的程序:無(wú)需額外工作,就可以獲得大量標(biāo)準(zhǔn)的行為。雖然這種輕松自由的行為并不總是完美的,但畢竟您可以無(wú)需太多工作就可以獲得很多好的架構(gòu)。

例如,Ruby on Rails 基于模型-視圖-控制器(Model-View-Controller,MVC)模式,這意味著大多數(shù) Rails 應(yīng)用程序都可以清晰地分成三個(gè)部分。模型部分包含了管理應(yīng)用程序數(shù)據(jù)所需的行為。

通常,在一個(gè) Ruby on Rails 應(yīng)用程序中,模型和數(shù)據(jù)庫(kù)表之間的關(guān)系是 1:1;Ruby on Rails 默認(rèn)使用的對(duì)象關(guān)系映射(ORM)ActiveRecord 負(fù)責(zé)管理模型與數(shù)據(jù)庫(kù)的交互,這意味著 Ruby on Rails 程序通常都具有(如果有的話)很少量的 SQL 代碼。

第二個(gè)部分是視圖,它包含創(chuàng)建發(fā)送至用戶的輸出所需要的代碼;它通常由 HTML、JavaScript 等組成。

最后的一個(gè)部分是控制器,它將來(lái)自用戶的輸入轉(zhuǎn)變?yōu)檎_的模型,然后使用適當(dāng)?shù)囊晥D呈現(xiàn)響應(yīng)。

Rails 的倡導(dǎo)者通常都樂(lè)于將其易用性方面的提高歸功于 MVC 范型 — 以及 Ruby 和 Rails 二者的其他一些特性,并稱很少有程序員能夠在較短的時(shí)間內(nèi)創(chuàng)建更多的功能。當(dāng)然,這意味著投入到軟件開(kāi)發(fā)的成本將能夠產(chǎn)生更多的商業(yè)價(jià)值,因此 Ruby on Rails 開(kāi)發(fā)愈發(fā)流行。

不過(guò),最初的開(kāi)發(fā)成本并不是事情的全部,還有其他的后續(xù)成本需要考慮,比如應(yīng)用程序運(yùn)行的維護(hù)成本和硬件成本。Ruby on Rails 開(kāi)發(fā)人員通常會(huì)使用測(cè)試和其他的敏捷開(kāi)發(fā)技術(shù)來(lái)降低維護(hù)成本,但是這樣一來(lái),很容易忽視具有大量數(shù)據(jù)的 Rails 應(yīng)用程序的有效運(yùn)行。雖然 Rails 能夠簡(jiǎn)化對(duì)數(shù)據(jù)庫(kù)的訪問(wèn),但它并不總是能夠如此有效。

Rails 應(yīng)用程序?yàn)楹芜\(yùn)行緩慢?

Rails 應(yīng)用程序之所以運(yùn)行緩慢,其中有幾個(gè)很基本的原因。第一個(gè)原因很簡(jiǎn)單:Rails 總是會(huì)做一些假設(shè)為您加速開(kāi)發(fā)。通常,這種假設(shè)是正確而有幫助的。不過(guò),它們并不總能有益于性能,并且還會(huì)導(dǎo)致資源使用的效率低下 — 尤其是數(shù)據(jù)庫(kù)資源。

例如,使用等同于 SELECT * 的一個(gè) SQL 語(yǔ)句,ActiveRecord 會(huì)默認(rèn)選擇查詢上的所有字段。在具有為數(shù)眾多的列的情況下 — 尤其是當(dāng)有些字段是巨大的 VARCHAR 或 BLOB 字段時(shí) — 就內(nèi)存使用和性能而言這種行為很有問(wèn)題。

另一個(gè)顯著的挑戰(zhàn)是 N+1 問(wèn)題,本文將對(duì)此進(jìn)行詳細(xì)的探討。這會(huì)導(dǎo)致很多小查詢的執(zhí)行,而不是一個(gè)單一的大查詢。例如,ActiveRecord 無(wú)從知道一組父記錄中的哪一個(gè)會(huì)請(qǐng)求一個(gè)子記錄,所以它會(huì)為每個(gè)父記錄生成一個(gè)子記錄查詢。由于每查詢的負(fù)荷,這種行為將導(dǎo)致明顯的性能問(wèn)題。

其他的挑戰(zhàn)則更多地與 Ruby on Rails 開(kāi)發(fā)人員的開(kāi)發(fā)習(xí)慣和態(tài)度相關(guān)。由于 ActiveRecord 能夠讓如此眾多的任務(wù)變得輕而易舉,Rails 開(kāi)發(fā)人員常常會(huì)形成 “SQL 不怎樣” 的一種態(tài)度,即便在更適合使用 SQL 的時(shí)候,也會(huì)避免 SQL。創(chuàng)建和處理數(shù)量巨大的 ActiveRecord 對(duì)象的速度會(huì)非常緩慢,所以在有些情況下,直接編寫(xiě)一個(gè)無(wú)需實(shí)例化任何對(duì)象的 SQL 查詢會(huì)更快些。

由于 Ruby on Rails 常被用來(lái)降低開(kāi)發(fā)團(tuán)隊(duì)的規(guī)模,又由于 Ruby on Rails 開(kāi)發(fā)人員通常都會(huì)執(zhí)行部署和維護(hù)生產(chǎn)中的應(yīng)用程序所需的一些系統(tǒng)管理任務(wù),因此若對(duì)應(yīng)用程序的環(huán)境知之甚少,就很可能出問(wèn)題。操作系統(tǒng)和數(shù)據(jù)庫(kù)有可能未被正確設(shè)置。比如,雖然并不最優(yōu),MySQL my.cnf 設(shè)置常常在 Ruby on Rails 部署內(nèi)保留它們的默認(rèn)設(shè)置。此外,可能還會(huì)缺少足夠的監(jiān)控和基準(zhǔn)測(cè)試工具來(lái)提供性能的長(zhǎng)期狀況。當(dāng)然,這并不是在責(zé)怪 Ruby on Rails 開(kāi)發(fā)人員;這是非專業(yè)化導(dǎo)致的后果;在有些情況下,Rails 開(kāi)發(fā)人員有可能是這兩個(gè)領(lǐng)域的專家。

最后一個(gè)問(wèn)題是 Ruby on Rails 鼓勵(lì)開(kāi)發(fā)人員在本地環(huán)境中進(jìn)行開(kāi)發(fā)。這么做有幾個(gè)好處 — 比如,開(kāi)發(fā)延遲的減少和分布性的提高 — 但它并不意味著您可以因?yàn)楣ぷ髡疽?guī)模的減少而只處理有限的數(shù)據(jù)集。他們?nèi)绾伍_(kāi)發(fā)以及代碼將被部署于何處之間的差異可能會(huì)是一個(gè)大問(wèn)題。即便您在一個(gè)性能良好的輕載本地服務(wù)器上處理小規(guī)模的數(shù)據(jù)已經(jīng)很長(zhǎng)一段時(shí)間,也會(huì)發(fā)現(xiàn)對(duì)于擁塞的服務(wù)器上的大型數(shù)據(jù)此應(yīng)用程序會(huì)有很明顯的性能問(wèn)題。

當(dāng)然,Rails 應(yīng)用程序具有性能問(wèn)題的原因可能有很多。查出 Rails 應(yīng)用程序有何潛在性能問(wèn)題的最佳方法是,利用能為您提供可重復(fù)、準(zhǔn)確度量的診斷工具。

檢測(cè)性能問(wèn)題

最好的工具之一是 Rails 開(kāi)發(fā)日志,它通常位于每個(gè)開(kāi)發(fā)機(jī)器上的 log/development.log 文件內(nèi)。它具有各種綜合指標(biāo):響應(yīng)請(qǐng)求所花費(fèi)的總時(shí)間、花費(fèi)在數(shù)據(jù)庫(kù)內(nèi)的時(shí)間所占的百分比、生成視圖所花時(shí)間的百分比等。此外,還有一些工具可用來(lái)分析此日志文件,比如 development-log-analyzer。 在生產(chǎn)期間,通過(guò)查看 mysql_slow_log 可以找到很多有價(jià)值的信息。

其中一個(gè)最強(qiáng)大也是最為有用的工具是 query_reviewer 插件。這個(gè)插件可顯示在頁(yè)面上有多少查詢?cè)趫?zhí)行以及頁(yè)面生成需要多長(zhǎng)時(shí)間。并且它還會(huì)自動(dòng)分析 ActiveRecord 生成的 SQL 代碼以便發(fā)現(xiàn)潛在問(wèn)題。

例如,它能找到不使用 MySQL 索引的查詢,所以如果您忘記了索引一個(gè)重要的列并由此造成了性能問(wèn)題,那么您將能很容易地找到這個(gè)列。此插件在一個(gè)彈出的

(只在開(kāi)發(fā)模式下可見(jiàn))中顯示了所有這類信息。

最后,不要忘記使用類似 Firebug、yslow、Ping 和 tracert 這樣的工具來(lái)檢測(cè)性能問(wèn)題是來(lái)自于網(wǎng)絡(luò)還是資源加載問(wèn)題。接下來(lái),讓我們來(lái)看具體的一些 Rails 性能問(wèn)題及其解決方案。

#p#

N+1 查詢問(wèn)題

N+1 查詢問(wèn)題是 Rails 應(yīng)用程序最大的問(wèn)題之一。例如,清單 1 內(nèi)的代碼能生成多少查詢?此代碼是一個(gè)簡(jiǎn)單的循環(huán),遍歷了一個(gè)假想的 post 表內(nèi)的所有 post,并顯示 post 的類別和它的主體。

  
 
 
  1. 清單 1. 未優(yōu)化的 Post.all 代碼  
  2. <%@posts = Post.all(@posts).each do |p|%>   
  3.  

    <%=p.category.name%> h1> 

  4.  

    <%=p.body%> p> 

  5. <%end%> 

答案:上述代碼生成了一個(gè)查詢外加 @posts 內(nèi)的每行一個(gè)查詢。由于每查詢的負(fù)荷,這可能會(huì)成為一個(gè)很大的挑戰(zhàn)。罪魁禍?zhǔn)资菍?duì) p.category.name 的調(diào)用。這個(gè)調(diào)用只應(yīng)用于該特定的 post 對(duì)象,而不是整個(gè) @posts 數(shù)組。幸好,通過(guò)使用立即加載,我們可以修復(fù)這個(gè)問(wèn)題。

立即加載 意味著 Rails 將自動(dòng)執(zhí)行所需的查詢來(lái)加載任何特定子對(duì)象的對(duì)象。Rails 將使用一個(gè) JOIN SQL 語(yǔ)句或一個(gè)執(zhí)行多個(gè)查詢的策略。不過(guò),假設(shè)指定了將要使用的所有子對(duì)象,那么將永遠(yuǎn)不會(huì)導(dǎo)致 N+1 的情形,在 N+1 情形下,一個(gè)循環(huán)的每個(gè)迭代都會(huì)生成額外的一個(gè)查詢。清單 2 是對(duì) 清單 1 內(nèi)代碼的修訂,它使用了立即加載來(lái)避免 N+1 問(wèn)題。

  
 
 
  1. 清單 2. 用立即加載優(yōu)化后的 Post.all 代碼  
  2. <%@posts = Post.find(:all, :include=>[:category]  
  3.  @posts.each do |p|%>   
  4.  

    <%=p.category.name%> h1> 

  5.  

    <%=p.body%> p> 

  6. <%end%> 

該代碼最多生成兩個(gè)查詢,而不管在此 posts 表內(nèi)有多少行。當(dāng)然,并不是所有情況都如此簡(jiǎn)單。處理復(fù)雜的 N+1 查詢情況需要更多的工作。那么做這么多努力值得么?讓我們來(lái)做一些快速的測(cè)試。

測(cè)試 N+1

使用清單 3 內(nèi)的腳本,可以發(fā)現(xiàn)查詢可以達(dá)到 — 多慢 — 或多快。 清單 3 展示了如何在一個(gè)獨(dú)立腳本中使用 ActiveRecord 來(lái)建立一個(gè)數(shù)據(jù)庫(kù)連接、定義表并加載數(shù)據(jù)。然后,可以使用 Ruby 的內(nèi)置基準(zhǔn)測(cè)試庫(kù)來(lái)查看哪種方式更快,快多少。

  
 
 
  1. 清單 3. 立即加載基準(zhǔn)測(cè)試腳本  
  2. require 'rubygems'  
  3. require 'faker'  
  4. require 'active_record'  
  5. require 'benchmark'  
  6.  
  7. # This call creates a connection to our database.  
  8.  
  9. ActiveRecord::Base.establish_connection(  
  10.  :adapter  => "mysql",  
  11.  :host     => "127.0.0.1",  
  12.  :username => "root", # Note that while this is the default setting for MySQL,  
  13.  :password => "",     # a properly secured system will have a different MySQL  
  14.                             # username and password, and if so, you'll need to  
  15.                             # change these settings.  
  16.  :database => "test")  
  17.  
  18. # First, set up our database...   
  19. class Category <  ActiveRecord::Base 
  20. end  
  21.  
  22. unless Category.table_exists?  
  23.  ActiveRecord::Schema.define do  
  24.   create_table :categories do |t|  
  25.     t.column :name, :string  
  26.   end  
  27.  end   
  28. end  
  29.  
  30. Category.create(:name=>'Sara Campbell\'s Stuff')  
  31. Category.create(:name=>'Jake Moran\'s Possessions')  
  32. Category.create(:name=>'Josh\'s Items')  
  33. number_of_categories = Category.count  
  34.  
  35. class Item <  ActiveRecord::Base   
  36.  belongs_to :category   
  37. end  
  38.  
  39. # If the table doesn't exist, we'll create it.  
  40.  
  41. unless Item.table_exists?  
  42.  ActiveRecord::Schema.define do  
  43.   create_table :items do |t|  
  44.     t.column :name, :string  
  45.     t.column :category_id, :integer   
  46.   end  
  47.  end   
  48. end  
  49.  
  50. puts "Loading data..."  
  51.  
  52. item_count = Item.count  
  53. item_table_size = 10000 
  54.  
  55. if item_count < item_table_size 
  56.  (item_table_size - item_count).times do  
  57.   Item.create!(:name=>Faker.name,   
  58.                  :category_id=>(1+rand(number_of_categories.to_i)))  
  59.  end  
  60. end  
  61.  
  62. puts "Running tests..."  
  63.  
  64. Benchmark.bm do |x|   
  65.  [100,1000,10000].each do |size|   
  66.   x.report "size:#{size}, with n+1 problem" do   
  67.    @items=Item.find(:all, :limit=>size)  
  68.    @items.each do |i|   
  69.     i.category  
  70.    end   
  71.   end   
  72.   x.report "size:#{size}, with :include" do   
  73.    @items=Item.find(:all, :include=>:category, :limit=>size)  
  74.    @items.each do |i|   
  75.     i.category  
  76.    end   
  77.   end   
  78.  end   
  79. end 

這個(gè)腳本使用 :include 子句測(cè)試在有和沒(méi)有立即加載的情況下對(duì) 100、1,000 和 10,000 個(gè)對(duì)象進(jìn)行循環(huán)操作的速度如何。為了運(yùn)行此腳本,您可能需要用適合于您的本地環(huán)境的參數(shù)替換此腳本頂部的這些數(shù)據(jù)庫(kù)連接參數(shù)。此外,需要?jiǎng)?chuàng)建一個(gè)名為 test 的 MySQL 數(shù)據(jù)庫(kù)。最后,您還需要 ActiveRecord 和 faker 這兩個(gè) gem,二者可通過(guò)運(yùn)行 gem install activerecord faker 獲得。 在我的機(jī)器上運(yùn)行此腳本生成的結(jié)果如清單 4 所示。

  
 
 
  1. 清單 4. 立即加載的基準(zhǔn)測(cè)試腳本輸出  
  2. -- create_table(:categories)  
  3.   -> 0.1327s  
  4. -- create_table(:items)  
  5.   -> 0.1215s  
  6. Loading data...  
  7. Running tests...  
  8.    user     system      total        real  
  9. size:100, with n+1 problem  0.030000   0.000000   0.030000 (  0.045996)  
  10. size:100, with :include  0.010000   0.000000   0.010000 (  0.009164)  
  11. size:1000, with n+1 problem  0.260000   0.040000   0.300000 (  0.346721)  
  12. size:1000, with :include  0.060000   0.010000   0.070000 (  0.076739)  
  13. size:10000, with n+1 problem  3.110000   0.380000   3.490000 (  3.935518)  
  14. size:10000, with :include  0.470000   0.080000   0.550000 (  0.573861) 

在所有情況下,使用 :include 的測(cè)試總是更為迅速 — 分別快 5.02、4.52 和 6.86 倍。當(dāng)然,具體的輸出取決于您的特定情況,但立即加載可明顯導(dǎo)致顯著的性能改善。

#p#

嵌套的立即加載

如果您想要引用一個(gè)嵌套的關(guān)系 — 關(guān)系的關(guān)系,又該如何呢? 清單 5 展示了這樣一個(gè)常見(jiàn)的情形:循環(huán)遍歷所有的 post 并顯示作者的圖像,其中 Author 與 Image 是 belongs_to 的關(guān)系。

  
 
 
  1. 清單 5. 嵌套的立即加載用例  
  2. @posts = Post.all   
  3. @posts.each do |p|    
  4.  

    <%=p.category.name%> h1> 

  5.  <%=image_tag p.author.image.public_filename %>   
  6.  

    <%=p.body%>   

  7.  <%end%>  

此代碼與之前一樣亦遭遇了相同的 N+1 問(wèn)題,但修復(fù)的語(yǔ)法卻沒(méi)有那么明顯,因?yàn)檫@里所使用的是關(guān)系的關(guān)系。那么如何才能立即加載嵌套關(guān)系呢?正確的答案是使用 :include 子句的哈希語(yǔ)法。清單 6 給出了使用哈希語(yǔ)法的一個(gè)嵌套的立即加載。

  
 
 
  1. 清單 6. 嵌套的立即加載解決方案  
  2. @posts = Post.find(:all, :include=>{ :category=>[],  
  3.         :author=>{ :image=>[]}} )  
  4. @posts.each do |p|    
  5.  

    <%=p.category.name%> h1> 

  6.  <%=image_tag p.author.image.public_filename %>   
  7.  

    <%=p.body%>   

  8.  <%end%>  

正如您所見(jiàn),您可以嵌套哈希和數(shù)組實(shí)量(literal)。請(qǐng)注意在本例中哈希和數(shù)組之間的惟一區(qū)別是哈??梢院星短椎淖訔l目,而數(shù)組則不能。否則,二者是等效的。

間接的立即加載

并非所有的 N+1 問(wèn)題都能很容易地察覺(jué)到。例如,清單 7 能生成多少查詢?

  
 
 
  1. 清單 7. 間接的立即加載示例用例  
  2. <%@user = User.find(5)  
  3.     @user.posts.each do |p|%>     
  4.       <%=render :partial=>'posts/summary',  :locals=>:post=>p  
  5.      %> <%end%> 

當(dāng)然,決定查詢的數(shù)量需要對(duì) posts/summary partial 有所了解。清單 8 中顯示了這個(gè) partial。

  
 
 
  1. 清單 8. 間接立即加載 partial: posts/_summary.html.erb   
  2. <%=post.user.name%> h1> 

不幸的是,答案是 清單 7 和 清單 8 在 post 內(nèi)每行生成一個(gè)額外查詢,查找用戶的名字 — 即便 post 對(duì)象由 ActiveRecord 從一個(gè)已在內(nèi)存中的 User 對(duì)象自動(dòng)生成。簡(jiǎn)言之,Rails 并不能關(guān)聯(lián)子記錄與其父記錄。

修復(fù)方法是使用自引用的立即加載。基本上,由于 Rails 重載由父記錄生成的子記錄,所以需要立即加載這些父記錄,就如同父與子記錄之間是完全分開(kāi)的關(guān)系一樣。代碼如清單 9 所示。

  
 
 
  1. 清單 9. 間接的立即加載解決方案  
  2. <%@user = User.find(5, :include=>{:posts=>[:user]})  
  3. ...snip... 

雖然有悖于直覺(jué),但這種技術(shù)與上述技術(shù)的工作原理大致相似。但是,很容易使用這種技術(shù)進(jìn)行過(guò)多的嵌套,尤其是在體系結(jié)構(gòu)復(fù)雜的情況下。簡(jiǎn)單的用例還好,比如 清單 9 內(nèi)所示的,但繁復(fù)的嵌套也會(huì)出問(wèn)題。在一些情況下,過(guò)多地加載 Ruby 對(duì)象有可能會(huì)比處理 N+1 問(wèn)題還要緩慢 — 尤其是當(dāng)每個(gè)對(duì)象并沒(méi)有被整個(gè)樹(shù)遍歷時(shí)。在該種情況下,N+1 問(wèn)題的其他解決方案可能更為適合。

一種方式是使用緩存技術(shù)。Rails V2.1 內(nèi)置了簡(jiǎn)單的緩存訪問(wèn)。使用 Rails.cache.read、 Rails.cache.write 及相關(guān)方法,可以輕松創(chuàng)建自己的簡(jiǎn)單緩存機(jī)制,并且后端可以是一個(gè)簡(jiǎn)單的內(nèi)存后端、一個(gè)基于文件的后端或一個(gè)分布式緩存服務(wù)器。

當(dāng)然,并不是所有的 Rails 問(wèn)題都與查詢的數(shù)量有關(guān)。

#p#

Rails 分組和聚合計(jì)算

您可能遇到的一個(gè)問(wèn)題是在 Ruby 所做的工作本應(yīng)由數(shù)據(jù)庫(kù)完成。這考驗(yàn)了 Ruby 的強(qiáng)大程度。很難想象在沒(méi)有任何重大激勵(lì)的情況下人們會(huì)自愿在 C 中重新實(shí)現(xiàn)其數(shù)據(jù)庫(kù)代碼的各個(gè)部分,但很容易在 Rails 內(nèi)對(duì) ActiveRecord 對(duì)象組進(jìn)行類似的計(jì)算。但是,Ruby 總是要比數(shù)據(jù)庫(kù)代碼慢。所以請(qǐng)不要使用純 Ruby 的方式執(zhí)行計(jì)算,如清單 10 所示。

  
 
 
  1. 清單 10. 執(zhí)行分組計(jì)算的不正確方式  
  2. all_ages = Person.find(:all).group_by(&:age).keys.uniq  
  3. oldest_age = Person.find(:all).max 

相反,Rails 提供了一系列的分組和聚合函數(shù)。可以像清單 11 所示的那樣使用它們。

  
 
 
  1. 清單 11. 執(zhí)行分組計(jì)算的正確方式  
  2. all_ages = Person.find(:all, :group=>[:age])    
  3. oldest_age = Person.calcuate(:max, :age) 

ActiveRecord::Base#find 有大量選項(xiàng)可用于模仿 SQL。更多信息可以在 Rails 文檔內(nèi)找到。注意,calculate 方法可適用于受數(shù)據(jù)庫(kù)支持的任何有效的聚合函數(shù),比如 :min、:sum 和 :avg。此外,calculate 能夠接受若干實(shí)參,比如 :conditions。查閱 Rails 文檔以獲得更詳細(xì)的信息。

不過(guò),并不是在 SQL 內(nèi)能做的所有事情在 Rails 內(nèi)也能做。如果插件不夠,可以使用定制 SQL。

用 Rails 定制 SQL

假設(shè)有這樣一個(gè)表,內(nèi)含人的職業(yè)、年齡以及在過(guò)去一年中涉及到他們的事故的數(shù)量??梢允褂靡粋€(gè)定制 SQL 語(yǔ)句來(lái)檢索此信息,如清單 12 所示。

  
 
 
  1. 清單 12. 用 ActiveRecord 定制 SQL 的例子  
  2. sql = "SELECT profession,  
  3.               AVG(age) as average_age,    
  4.               AVG(accident_count)   
  5.          FROM persons   
  6.         GROUP   
  7.            BY profession"  
  8.  
  9. Person.find_by_sql(sql).each do |row|     
  10.   puts "#{row.profession}, " << 
  11.        "avg. age: #{row.average_age}, " << 
  12.        "avg. accidents: #{row.average_accident_count}"  
  13. end 

這個(gè)腳本應(yīng)該能生成清單 13 所示的結(jié)果。

  
 
 
  1. 清單 13. 用 ActiveRecord 定制 SQL 的輸出  
  2. Programmer, avg. age: 18.010, avg. accidents: 9  
  3. System Administrator, avg. age: 22.720, avg. accidents: 8 

當(dāng)然,這是最簡(jiǎn)單的例子。您可以自己想象一下如何能將此例中的 SQL 擴(kuò)展成一個(gè)有些復(fù)雜性的 SQL 語(yǔ)句。您還可以使用 ActiveRecord::Base.connection.execute 方法運(yùn)行其他類型的 SQL 語(yǔ)句,比如 ALTER TABLE 語(yǔ)句,如清單 14 所示。

  
 
 
  1. 清單14. 用 ActiveRecord 定制非查找型 SQL  
  2. ActiveRecord::Base.connection.execute "ALTER TABLE some_table CHANGE COLUMN..." 

大多數(shù)的模式操作,比如添加和刪除列,都可以使用 Rails 的內(nèi)置方法完成。但如果需要,也可以使用執(zhí)行任意 SQL 代碼的能力。

結(jié)束語(yǔ)

與所有的框架一樣,如果不多加小心和注意,Ruby on Rails 也會(huì)遭遇性能問(wèn)題。所幸的是,監(jiān)控和修復(fù)這些問(wèn)題的技術(shù)相對(duì)簡(jiǎn)單且易學(xué),而且即便是復(fù)雜的問(wèn)題,只要有耐心并對(duì)性能問(wèn)題的源頭有所了解,也是可以解決的。

原文作者:David Berube

原文鏈接:http://www.ibm.com/developerworks/cn/opensource/os-railsn1/index.html

【編輯推薦】

  1. Ruby on Rails性能優(yōu)化七劍
  2. 基于Ruby On Rails開(kāi)發(fā)高品質(zhì)Web應(yīng)用
  3. Ruby on Rails應(yīng)用技巧全解析
  4. 大改動(dòng)小變化 Ruby On Rails 3蓄勢(shì)待發(fā)
  5. 跑起來(lái)吧 Ruby on Rails開(kāi)發(fā)初體驗(yàn)

責(zé)任編輯:王曉東
來(lái)源: IBM DW Ruby on Rails


當(dāng)前題目:加速RubyonRails消除N+1查詢問(wèn)題
網(wǎng)頁(yè)鏈接:http://www.5511xx.com/article/dhgjsod.html