私はPostgreSQL 8.4でRails 3.1を使用しています。 GUIDプライマリキーを使用する必要があると仮定しましょう。 1つの潜在的な欠点は、インデックスの断片化です。 MS SQLでは、特別なシーケンシャルGUIDを使用することをお勧めします。シーケンシャルGUIDへの1つのapproachは、GUIDの最後のMACアドレス部分に6バイトのタイムスタンプを代入するCOMBination GUIDです。これにはいくつかの主流が採用されています.COMBはNHibernate(NHibernate/Id/GuidCombGenerator.cs)でネイティブに利用できます。主キーのGUIDを使用する場合、COMB GUIDはRails 3.1で良いアイデアですか?
私は(UUIDToolsの助けを借り2.1.2宝石に)Railsの中でCOMBのGUIDを作成する方法を考え出したが、それはいくつかの未回答の質問を残し思う:
- んPostgreSQLはインデックスの断片化に苦しみますプライマリキーがタイプUUIDの場合
- GUIDの下位6バイトがシーケンシャルの場合、フラグメンテーションが回避されますか?
- COMB GUIDは、RailsでシーケンシャルGUIDを作成するための許容可能で信頼できる方法の下に実装されていますか?
あなたのご意見ありがとうございます。
create_contacts.rb
マイグレーション
class CreateContacts < ActiveRecord::Migration
def up
create_table :contacts, :id => false do |t|
t.column :id, :uuid, :null => false # manually create :id with underlying DB type UUID
t.string :first_name
t.string :last_name
t.string :email
t.timestamps
end
execute "ALTER TABLE contacts ADD PRIMARY KEY (id);"
end
# Can't use reversible migration because it will try to run 'execute' again
def down
drop_table :contacts # also drops primary key
end
end
/app/models/contact.rb
class Contact < ActiveRecord::Base
require 'uuid_helper' #rails 3 does not autoload from lib/*
include UUIDHelper
set_primary_key :id
end
/lib/uuid_tools.rb
require 'uuidtools'
module UUIDHelper
def self.included(base)
base.class_eval do
include InstanceMethods
attr_readonly :id # writable only on a new record
before_create :set_uuid
end
end
module InstanceMethods
private
def set_uuid
# MS SQL syntax: CAST(CAST(NEWID() AS BINARY(10)) + CAST(GETDATE() AS BINARY(6)) AS UNIQUEIDENTIFIER)
# Get current Time object
utc_timestamp = Time.now.utc
# Convert to integer with milliseconds: (Seconds since Epoch * 1000) + (6-digit microsecond fraction/1000)
utc_timestamp_with_ms_int = (utc_timestamp.tv_sec * 1000) + (utc_timestamp.tv_usec/1000)
# Format as hex, minimum of 12 digits, with leading zero. Note that 12 hex digits handles to year 10889 (*).
utc_timestamp_with_ms_hexstring = "%012x" % utc_timestamp_with_ms_int
# If we supply UUIDTOOLS with a MAC address, it will use that rather than retrieving from system.
# Use a regular expression to split into array, then insert ":" characters so it "looks" like a MAC address.
UUIDTools::UUID.mac_address = (utc_timestamp_with_ms_hexstring.scan /.{2}/).join(":")
# Generate Version 1 UUID (see RFC 4122).
comb_guid = UUIDTools::UUID.timestamp_create().to_s
# Assign generted COMBination GUID to .id
self.id = comb_guid
# (*) A note on maximum time handled by 6-byte timestamp that includes milliseconds:
# If utc_timestamp_with_ms_hexstring = "FFFFFFFFFFFF" (12 F's), then
# Time.at(Float(utc_timestamp_with_ms_hexstring.hex)/1000).utc.iso8601(10) = "10889-08-02T05:31:50.6550292968Z".
end
end
end
Re: "レール3はlib/*から自動ロードされません";あなたが 'config.autoload_paths + =%W(#{config.root}/lib)'を実行した場合はそれが実行されます。 – qerub