{"id":12,"date":"2007-02-03T20:29:36","date_gmt":"2007-02-03T19:29:36","guid":{"rendered":"http:\/\/schuerig.de\/michael\/blog\/?p=12"},"modified":"2021-11-24T09:20:10","modified_gmt":"2021-11-24T08:20:10","slug":"ar-enumerable","status":"publish","type":"post","link":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/2007\/02\/03\/ar-enumerable\/","title":{"rendered":"ActiveRecord Enumerable"},"content":{"rendered":"<p>Ever wanted to iterate over a huge number of objects and found<br \/>\nthat <code>find(:all)<\/code> doesn&#8217;t cut it? Then this plugin<br \/>\nmight be for you. Install it with<\/p>\n<p><code><\/p>\n<pre>\r\n$ script\/plugin install svn:\/\/rubyforge.org\/var\/svn\/ar-enumerable\/ar_enumerable\/trunk\r\n<\/pre>\n<p><\/code><\/p>\n<p>First, a note of caution. This plugin has not seen much practical<br \/>\nuse yet, in its current state it is only slightly above a<br \/>\nproof-of-concept. There are several tests included that cover most<br \/>\nof the functionality. If you intend to use this plugin, please<br \/>\nmake sure to independently check that it does what you want.<\/p>\n<h3>Enumerating ActiveRecord objects<\/h3>\n<p>Let&#8217;s start with a boring example, to get the general idea<\/p>\n<p><code><\/p>\n<pre>\r\nPerson.where(['lastname = ?', 'Smith']).map(&:firstname)\r\n<\/pre>\n<p><\/code><\/p>\n<p>Slightly more interesting<\/p>\n<p><code><\/p>\n<pre>\r\nPerson.where(['lastname = ?', 'Smith']).inject(0) do |income, person|\r\n  income += person.income\r\nend\r\n<\/pre>\n<p><\/code><\/p>\n<p><code><\/p>\n<pre>\r\nsiblings = Person.where(\r\n    ['lastname = ?', 'Smith'], \r\n    :include =&gt; :siblings).inject([0, 0]) do |memo, person|\r\n  memo[0] += person.siblings.count\r\n  memo[1] += 1\r\n  memo\r\nend\r\nsiblings[0].to_f \/ siblings[1]\r\n<\/pre>\n<p><\/code><\/p>\n<p>The point here is that your database may contain millions of Smiths,<br \/>\nfor what it&#8217;s worth, the entire population of the earth could have<br \/>\nturned into Smiths, still, only a limited number of them would be<br \/>\nloaded into memory at the same time.<\/p>\n<p>Internally, enumeration works in two completely different ways.<br \/>\nBy default, a chunk of objects is retrieved from the database using<br \/>\nOFFSET and LIMIT clauses. This way is supported by all databases,<br \/>\nhowever it can be slow.<br \/>\nTherefore, the preferred alternative is to use a standard SQL cursor<br \/>\nfor iterating over the result set of a query. It would simply look like<br \/>\nthis<\/p>\n<p><code><\/p>\n<pre>\r\nPerson.where(['lastname = ?', 'Smith'], :use_cursor =&gt; true).inject(0) do |income, person|\r\n  income += person.income\r\nend\r\n<\/pre>\n<p><\/code><\/p>\n<p>A further parameter is how many records (or rows, in the case of cursors)<br \/>\nare fetched from the database in one access. The default is 1000. You can<br \/>\nset it explicitly like this<\/p>\n<p><code><\/p>\n<pre>\r\nPerson.where(['lastname = ?', 'Smith'], :fetch_count =&gt; 100).inject(0) do |income, person|\r\n  income += person.income\r\nend\r\n<\/pre>\n<p><\/code><\/p>\n<h3>Performance Considerations<\/h3>\n<p>Some informal tests suggest that for large result sets without<br \/>\nincluded associations cursor-based enumeration can be faster than<br \/>\nOFFSET\/LIMIT-based enumeration by a factor of 3 to 5.<br \/>\nWhen associations are included, things become more blurry. In this<br \/>\ncase, cursor-based enumeration imposes an ordering on the result<br \/>\nset that can slow down things considerably.<br \/>\nThe fetch count has considerable influence on performance, basically,<br \/>\nyou can buy speed by spending memory.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Ever wanted to iterate over a huge number of objects and found that find(:all) doesn&#8217;t cut it? Then this plugin might be for you. Install it with $ script\/plugin install svn:\/\/rubyforge.org\/var\/svn\/ar-enumerable\/ar_enumerable\/trunk First, a note of caution. This plugin has not &hellip; <a href=\"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/2007\/02\/03\/ar-enumerable\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-12","post","type-post","status-publish","format-standard","hentry","category-rails"],"_links":{"self":[{"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/posts\/12","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=12"}],"version-history":[{"count":1,"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/posts\/12\/revisions"}],"predecessor-version":[{"id":149,"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/posts\/12\/revisions\/149"}],"wp:attachment":[{"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=12"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=12"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.schuerig.de\/michael\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=12"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}