2009-02-26 55 views
4

我正在使用rails與oracleenhanced適配器爲傳統應用程序創建新接口。Rails:rake db:migrate * very * slow on Oracle

數據庫遷移成功完成,但是在耙取完成之前需要花費非常長的時間。數據庫更改發生得非常快(1或2秒),但db/schema.db轉儲需要一個多小時才能完成。 (請參閱下面的示例遷移。)

這是一個相對較大的模式(大約150個表),但我相信不應花這麼長時間才能轉儲出每個表的描述。

有沒有辦法通過只取最後的schema.db並應用遷移中指定的更改來加速?或者我能夠完全跳過這個模式轉儲?

我明白這個schema.db是用來從頭開始創建測試數據庫,但是這種情況下,表格觸發器中有很大一部分數據庫邏輯,它們不包含在schema.rb之內,所以耙測試是在任何情況下對我們都沒有好處。 (這是一個完全不同的問題,我需要一些其他的點進行梳理。)

 
[email protected]:~/rails/voyager$ time rake db:migrate 
(in /home/dgs/rails/voyager) 
== 20090227012452 AddModuleActionAndControllerNames: migrating ================ 
-- add_column(:modules, :action_name, :text) 
    -> 0.9619s 
    -> 0 rows 
-- add_column(:modules, :controller_name, :text) 
    -> 0.1680s 
    -> 0 rows 
== 20090227012452 AddModuleActionAndControllerNames: migrated (1.1304s) ======= 


real 87m12.961s 
user 0m12.949s 
sys 0m2.128s 

回答

4

畢竟遷移應用到數據庫,然後耙分貝:遷移電話分貝:模式:轉儲任務生成schema.rb文件從當前數據庫架構。

db:schema:dump調用適配器的「tables」方法獲取所有表的列表,然後爲每個表調用「indexes」方法和「columns」方法。您可以在activerecord-oracle_enhanced-adapter gem的oracle_enhanced_adapter.rb文件中找到在這些方法中使用的SQL SELECT語句。基本上它從ALL%或USER%數據字典表中選擇來查找所有信息。

最初我在使用具有很多不同架構的數據庫時遇到了原始Oracle適配器的問題(因爲性能可能會受到數據庫中表的總數 - 而不僅僅是在您的架構中)的影響,因此我做了一些Oracle增強適配器中的優化。在你的情況下找出哪些方法很慢(我懷疑它可能是針對每個表執行的「索引」或「列」方法)是很好的。

調試此問題的一種方法是如果您將一些調試消息放入oracle_enhanced_adapter.rb文件中,以便您可以確定哪些方法調用需要這麼長時間。

+0

很酷。我將在oracle_enhanced_adapter.rb中發揮一下,看看我能找到什麼。 我懷疑它被綁定到模式中,因爲在數據庫中有許多具有不同名稱的相同模式。 乾杯 – 2009-03-02 20:22:16

2

問題大多在oracle_enhanced_adapter.rb挖了一圈之後就解決了。

問題歸結爲本地模式中太多的表(很多EBA_%, EVT_%, EMP_%, SMP_%表已經在那裏同時創建),轉儲中包含存檔表以及從數據字典中選擇需要14秒到執行。

要解決的速度,我做了三件事情:

  1. 的下降,從架構轉儲所有不必要的表(約250拿出500)
  2. 排除存檔表
  3. 緩存長的結果正在運行的查詢

這將從其餘350個表的遷移/模式轉儲的時間從大約90分鐘提高到大約15秒。速度不夠快。我的代碼如下(靈感沒有複製和粘貼 - 這段代碼對我的數據庫非常具體,但你應該能夠明白)。您需要手動創建臨時表。我需要大約2或3分鐘的時間 - 每次遷移產生的時間仍然很長,無論如何都相當靜止=)

module ActiveRecord 
    module ConnectionAdapters 
    class OracleEnhancedAdapter 
     def tables(name = nil) 
     select_all("select lower(table_name) from all_tables where owner = sys_context('userenv','session_user') and table_name not like 'A!_%' escape '!' ").inject([]) do | tabs, t | 
      tabs << t.to_a.first.last 
     end 
     end 


     # TODO think of some way to automatically create the rails_temp_index table 
     # 
     # Table created by: 
     # create table rails_temp_index_table as 
     # SELECT lower(i.index_name) as index_name, i.uniqueness, 
     #   lower(c.column_name) as column_name, i.table_name 
     # FROM all_indexes i, user_ind_columns c 
     # WHERE c.index_name = i.index_name 
     #  AND i.owner = sys_context('userenv','session_user') 
     #  AND NOT exists (SELECT uc.index_name FROM user_constraints uc 
     #    WHERE uc.constraint_type = 'P' and uc.index_name = i.index_name); 

     def indexes(table_name, name = nil) #:nodoc: 

       result = select_all(<<-SQL, name) 
       SELECT index_name, uniqueness, column_name 
        FROM rails_temp_index_table 
       WHERE table_name = '#{table_name.to_s.upcase}' 
        ORDER BY index_name 
       SQL 

       current_index = nil 
       indexes = [] 

      result.each do |row| 
       if current_index != row['index_name'] 
        indexes << IndexDefinition.new(table_name, row['index_name'], row['uniqueness'] == "UNIQUE", []) 
        current_index = row['index_name'] 
       end 

       indexes.last.columns << row['column_name'] 
       end 

       indexes 
      end 
end