2009-02-26 85 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