[Nitro] OG vs Active Record

Bill Kelly billk at cts.com
Mon Aug 20 14:16:15 EDT 2007


From: "Robert Mela" <rob at robmela.com>
>
> If you want speed you need to be very careful about how you use ORMs 
> with large datasets.
> 
> I recently found an ActiveRecord retrieval that made 8 thousand 
> individual database calls totally 4 megabytes of generated SQL.   All 
> calls were to the same, self-referential table.

When I've run into issues like this with Og, I've just written a
custom SQL query.

This particular example doesn't exactly parallel your problem, but
it does show using refers_to to keep the data normalized; and shows
how to ask Og for particular table names and such needed to construct
the custom query:


class IPHost
  property :ip, String, :unique => true
  property :hostname, String
end

class Playername
  property :playername, String, :unique => true
end

class Servername
  property :servername, String, :unique => true
end

class SuicidesAllTime
  property :method, String      # ex: mg, cg, trap, phalanx, lava, squished, cratered, drowned
  property :date, Date
  property :count, Integer
  refers_to :servername, Servername
  refers_to :victim, Playername

  def self.top_suicides_list(victim_name_str, method_str, servername_str, date=Date.today, limit=10)
    date = get_insert_date(date)
    __total__ = STATS_TOTAL_NAME
    
    @playername_total ||= Playername.find_or_create_by_playername(__total__)
    @servername_total ||= Servername.find_or_create_by_servername(__total__)
    date_str = "#{date.year}-#{date.month}-#{date.mday}"

    if victim_name_str.nil?
      victim = nil
    elsif victim_name_str == __total__
      victim = @playername_total
    else
      victim = PlayerSeen.find_closest_playername(victim_name_str)
      return [] unless victim
    end
    
    if servername_str.nil?
      servername = nil
    elsif servername_str == __total__
      servername = @servername_total
    else
      servername = Servername.find_by_servername(servername_str)
      return [] unless servername
    end

    ptotal = @playername_total
    stotal = @servername_total

    sql =
      "SELECT P1.playername AS victim, " +
             "FRAG.method, SV.servername AS server, FRAG.count " +
        "FROM #{self.table} FRAG, #{Playername.table} P1, " +
             "#{Servername.table} SV " +
       "WHERE " +
         (victim ? "FRAG.victim_oid = #{victim.oid}" : "FRAG.victim_oid <> #{ptotal.oid}") +
        " AND " + (servername ? "FRAG.servername_oid = #{servername.oid}" : "FRAG.servername_oid <> #{stotal.oid}") +
        " AND " + (method_str ? "FRAG.method = '#{method_str}'" : "FRAG.method <> '#{__total__}'") +
        " AND FRAG.date = '#{date_str}' " +
         "AND P1.oid = FRAG.victim_oid " +
         "AND SV.oid = FRAG.servername_oid " +
         "ORDER BY FRAG.count DESC"
    sql << " LIMIT #{limit}" if limit
    res = ogstore.query(sql)
    rows = []
    res.each_row {|row,dummy| rows << row}
    rows
  end

  # ...

end


Dunno if this is useful to anyone; but so far it's been possible for 
me to use Og to do most of the work, and just write custom queries as
I need them.


Regards,

Bill




More information about the Nitro-general mailing list