Вопрос

Я использую рельсы с oracleenhanced адаптер для создания нового интерфейса для устаревшего приложения.

Миграция базы данных работает успешно, но до завершения работы rake требуется невероятно много времени.Изменения в базе данных происходят довольно быстро (1-2 секунды), но db/schema.db создание дампа занимает более часа.(См. пример миграции ниже.)

Это относительно большая схема (около 150 таблиц), но я уверен, что выгрузка описания каждой таблицы не займет много времени.

Есть ли способ ускорить это, просто взяв последний schema.db и применить к нему изменение, указанное при миграции?Или я могу вообще пропустить этот дамп схемы?

Я понимаю это schema.db используется для создания тестовой базы данных каждый раз с нуля, но в этом случае большая часть логики базы данных содержится в триггерах таблиц, которые не включены в триггеры таблиц. schema.rb в любом случае, так что рейк-тесты нам в любом случае ни к чему.(Это совершенно другая проблема, которую мне нужно будет решить в какой-то другой момент.)

dgs@dgs-laptop:~/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
Это было полезно?

Решение

После того, как все миграции применены к базе данных, rake db:migrate вызывает задачу db:schema:dump для создания файла Schema.rb из текущей схемы базы данных.

db:schema:dump вызывает метод «tables» адаптера, чтобы получить список всех таблиц, затем для каждой таблицы вызывает метод «indexes» и метод «columns».Вы можете найти инструкции SQL SELECT, которые используются в этих методах, в файле oracle_enhanced_adapter.rb гема activerecord-oracle_enhanced-adapter.По сути, он выбирает из таблиц словаря данных ALL% или USER%, чтобы найти всю информацию.

Первоначально у меня были проблемы с исходным адаптером Oracle, когда я использовал его с базами данных с множеством различных схем (поскольку на производительность могло влиять общее количество таблиц в базе данных, а не только в вашей схеме), и поэтому я провел некоторые оптимизации в Oracle Enhanced. адаптер.Было бы хорошо узнать, какие методы в вашем случае медленные (я подозреваю, что это может быть метод «индексов» или «столбцов», который выполняется для каждой таблицы).

Один из способов отладки этой проблемы — поместить несколько отладочных сообщений в файл oracle_enhanced_adapter.rb, чтобы можно было определить, какие вызовы методов занимают так много времени.

Другие советы

Проблема в основном решена после некоторых копаний 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top