4

我正在使用带有oracleenhanced适配器的 rails 为遗留应用程序创建新接口。

数据库迁移成功,但在 rake 完成之前需要非常长的时间。数据库更改发生得非常快(1 或 2 秒),但db/schema.db转储需要一个多小时才能完成。(请参阅下面的示例迁移。)

这是一个相对较大的模式(大约 150 个表),但我确信转储每个表描述不应该花这么长时间。

schema.db有没有办法通过只取最后一个并将迁移中指定的更改应用于它来加快速度?或者我可以完全跳过这个模式转储吗?

我知道这schema.db用于每次从头开始创建测试数据库,但是在这种情况下,表触发器中有很大一部分数据库逻辑schema.rb无论如何都不包含在其中,因此 rake 测试对我们没有任何好处案子。(这是一个完全不同的问题,我需要在其他时候解决。)

dgs@dgs-laptop:~/rails/voyager$ time rake db:migrate
(在 /home/dgs/rails/voyager 中)
== 20090227012452 AddModuleActionAndControllerNames:迁移 ================
-- add_column(:modules, :action_name, :text)
   -> 0.9619s
   -> 0 行
-- add_column(:modules, :controller_name, :text)
   -> 0.1680 秒
   -> 0 行
== 20090227012452 AddModuleActionAndControllerNames:迁移(1.1304s)=======


真正的 87m12.961s
用户 0m12.949s
系统 0m2.128s
4

2 回答 2

4

将所有迁移应用到数据库后,rake db:migrate 调用 db:schema:dump 任务从当前数据库模式生成 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 文件中,以便您可以确定哪些方法调用需要这么长时间。

于 2009-02-27T21:08:55.627 回答
2

经过一番深入研究后,问题基本解决了oracle_enhanced_adapter.rb

问题归结为本地模式中的表太多(许多EBA_%, EVT_%, EMP_%, SMP_%表是在某个时候同时创建的),存档表包含在转储中,并且从数据字典中选择需要 14 秒才能执行。

为了提高速度,我做了三件事:

  1. 删除了所有不需要的表(500 个中的大约 250 个)
  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
于 2009-03-31T00:52:08.030 回答