2011年7月6日水曜日

rails on oracle (oracleで接続する手順) その2

■概要

rails on oracle でいくつかのテーマで検証してみます

●fetchループ

module FetchTest
  SQL = "select p1.* from posts p1 cross join posts p2"
  def self.run
    Post.delete_all
    200.times do |i|
      Post.create(:title => "title_#{i}", :body => "body_#{i}")
    end
    open("test.txt", "w") do |f|
      # ① Post.find_by_sql(SQL).each { |r| f.write "#{r}\r\n" }
      # ② Post.connection.raw_connection.exec(SQL) { |r| f.write "#{r}\r\n" }
    end
  end
end

FetchTest.run

上記の場合①は通常の検索処理。sqlの実行結果を全てメモリ上に展開します。
②の場合、fetchループで繰り返し処理が発生する為、"同時に必要となるメモリ"は少なくてすみます。

# それぞれ実行しながら、topコマンド等でメモリ利用状況を確認しましょう。

よって大量のcsv出力する場合は必ず②のようにする必要があります。

●DROP

railsで実装する場合、割と頻繁にDBスキーマの全削除、再作成をするかと思います(うちだけ?)。その際の機能は充実してきており、adapter内で多数のDROP文が実装されています。

但し適宜 purge recyclebin してあげないとゴミがたまりそうです。

●indexの表領域

性能向上の為、データ/インデックスを別HDDに保存する場合、データ/インデックスで表領域を分ける必要があります。oracle_enhanced_adapterは成長しており、migrationで

add_index :posts, :title, :tablespace => 'foo'

のように指定できます。

●varchar2問題

oracleのvarchar2/char2は歴史的な経緯で、"バイト単位"での長さ指定になります。
よってrailsからスキーマ作成する際は、string => nvarchar2へのマッピングを以前はしていたのですが、最近のoracle enhanced adapterは進化しています!

lib/active_record/connection_adapters/oracle_enhanced_adapter.rb によれば、nls_length_semantics というオプションがデフォルトで'CHAR'となっており、このオプションを指定する事によってvarchar2/char2を文字数単位で長さ指定出来る様になります。

よって何も考えなくても、mysql等と同じように指定できる様になりました。
実際下記の用にスキーマが出来ています。
SQL> desc posts;
 名前                     NULL?    型
 -------------------------- -------- ----------------------------
 ID                         NOT NULL NUMBER(38)
 TITLE                               VARCHAR2(255 CHAR) <= CHARで255
 BODY                                CLOB
 CREATED_AT                          DATE
 UPDATED_AT                          DATE
●oracle enhanced adapter独自項目の設定 oracle enhanced adapterには独自の設定項目があり...と思ったら良いページがありました。一部ソースを読んだ結果下記の様です。
# config/initializers/oracle.rb 等に下記内容を設置
ActiveSupport.on_load(:active_record) do
  ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.class_eval do
    # NUMBER(1)をbooleanにマッピングするか
    self.emulate_booleans = true
    # DATE型を(rubyの)Date型にマッピングするか
    self.emulate_dates = false
    # カラム名が(^|_)date(_|$)とマッチする場合Date型にマッピングするか
    self.emulate_dates_by_column_name = false
    # カラム名が(^|_)idとマッチする場合Integer型にマッピングするか
    self.emulate_integers_by_column_name = true
    # CHAR(1)かVARCHAR(1)、またはカラム名が_FLAG/_YNで終了する場合Booleanにマッピングするか
    self.emulate_booleans_from_strings = true
    # シーケンサー作成する際のオプションを指定する
    self.default_sequence_start_value = "1 NOCACHE INCREMENT BY 1"
  end
end
●雑感
ソース見て思ったのですが、oracle enhanced adapter マジで進化してます!
かなりきっちりしてる感じです(識別子30文字制限問題、in句の1000上限問題 ...etc)

0 件のコメント:

コメントを投稿