• Stars
    star
    154
  • Rank 242,095 (Top 5 %)
  • Language
    Ruby
  • License
    MIT License
  • Created about 10 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

N+1 count query killer for ActiveRecord

ActiveRecord::Precount Build Status

N+1 count query killer for ActiveRecord. Yet another counter_cache alternative.
ActiveRecord::Precount allows you to cache count of associated records by eager loading.

Project Status

Softly deprecated in favor of activerecord-precounter.

Major features of activerecord-precount are working with ActiveRecord 5.1, but it has no active maintainer (it's welcome that you become the one) and its design is fragile to ActiveRecord internal changes.

activerecord-precounter is strong for ActiveRecord internal changes and now it's recommended to use it instead.

Synopsis

N+1 count query

Sometimes you may see many count queries for one association. You can use counter_cache to solve it, but it costs much to use counter_cache.

Tweet.all.each do |tweet|
  p tweet.favorites.count
end
# SELECT `tweets`.* FROM `tweets`
# SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 1
# SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 2
# SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 3
# SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 4
# SELECT COUNT(*) FROM `favorites` WHERE `favorites`.`tweet_id` = 5

Count eager loading

precount

With activerecord-precount gem installed, you can use precount method to eagerly load counts of associated records. Like preload, it loads counts by multiple queries

Tweet.all.precount(:favorites).each do |tweet|
  p tweet.favorites_count
end
# SELECT `tweets`.* FROM `tweets`
# SELECT COUNT(`favorites`.`tweet_id`), `favorites`.`tweet_id` FROM `favorites` WHERE `favorites`.`tweet_id` IN (1, 2, 3, 4, 5) GROUP BY `favorites`.`tweet_id`

eager_count

Like eager_load, eager_count method allows you to load counts by one JOIN query.

Tweet.all.eager_count(:favorites).each do |tweet|
  p tweet.favorites_count
end
# SELECT `tweets`.`id` AS t0_r0, `tweets`.`tweet_id` AS t0_r1, `tweets`.`user_id` AS t0_r2, `tweets`.`created_at` AS t0_r3, `tweets`.`updated_at` AS t0_r4, COUNT(`favorites`.`id`) AS t1_r0 FROM `tweets` LEFT OUTER JOIN `favorites` ON `favorites`.`tweet_id` = `tweets`.`id` GROUP BY tweets.id

Benchmark

The result of this benchmark.

N+1 query precount eager_count
Time 1.401 0.176 0.119
Ratio 1.0x 7.9x faster 11.7x faster
# Tweet count is 50, and each tweet has 10 favorites
Tweet.all.map{ |t| t.favorites.count }                # N+1 query
Tweet.precount(:favorites).map(&:favorites_count)     # precount
Tweet.eager_count(:favorites).map(&:favorites_count)  # eager_count

Installation

Add this line to your application's Gemfile:

gem 'activerecord-precount'

Supported Versions

  • Ruby
    • 2.1, 2.2, 2.3
  • Rails
    • 4.2, 5.0
  • Databases
    • sqlite
    • mysql
    • postgresql

Advanced Usage

Nested eager loading

Foo.precount(:bars) or Foo.eager_count(:bars) automatically defines bars_count association for Foo. That enables you to preload the association and call foo.bars_count.

You can manually define bars_count with following code.

 class Foo < ActiveRecord::Base
-  has_many :bars
+  has_many :bars, count_loader: true
 end

Then there are two different ways to preload the bars_count.

# the same
Foo.preload(:bars_count)
Foo.precount(:bars)

With this condition, you can eagerly load nested association by preload.

Hoge.preload(foo: :bars_count)

count method is not recommended

With activerecord-precount gem installed, bars.count fallbacks to bars_count if bars_count is defined. Though precounted bars.count is faster than not-precounted one, the fallback is currently much slower than just calling bars_count.

# slow
Foo.precount(:bars).map { |f| f.bars.count }
Foo.eager_count(:bars).map { |f| f.bars.count }

# fast (recommended)
Foo.precount(:bars).map { |f| f.bars_count }
Foo.eager_count(:bars).map { |f| f.bars_count }

License

MIT License

More Repositories

1

pp

Colored pretty printer for Go language
Go
1,679
star
2

hamlit

High Performance Haml Implementation
Ruby
979
star
3

md2key

Convert markdown to keynote
Ruby
977
star
4

xremap

Key remapper for X11 and Wayland
Rust
770
star
5

Nocturn

Multi-platform Twitter Client built with React, Redux and Electron
JavaScript
714
star
6

gitstar-ranking

GitHub star ranking for users, organizations and repositories
Kotlin
700
star
7

llrb

LLVM-based JIT Compiler for Ruby
C
303
star
8

rack-user_agent

Rack::Request extension for handling User-Agent
Ruby
187
star
9

activerecord-precounter

Yet Another N+1 COUNT Query Killer for ActiveRecord
Ruby
102
star
10

go-ansi

Windows-portable ANSI escape sequence utility for Go language
Go
85
star
11

tetris

TETRIS for your terminal
Go
76
star
12

yarv-mjit

MRI method JIT compiler based on original stack-based YARV instructions (Development Repository of ruby/ruby#1782, already merged)
Ruby
65
star
13

itamae-plugin-recipe-rbenv

Itamae/MItamae plugin to install ruby with rbenv
Ruby
56
star
14

jjvm

JVM implementation written in Java
Java
53
star
15

karabiner-ruby

Lightweight keyremap configuration DSL for Karabiner
Ruby
53
star
16

ruby-jit-challenge

Tutorial to write a Ruby JIT
Ruby
51
star
17

itamae-go

Go implementation of itamae embedding mruby
Go
50
star
18

dotfiles

Bootstrap development environment
Shell
49
star
19

hescape

C library for fast HTML escape using SSE instructions
C
48
star
20

railsbench

Rails 6.1 version of headius/pgrailsbench with database seeds
Ruby
43
star
21

gem-default

Change a non-default gem to a default gem in your local environment
Ruby
37
star
22

rebuild

Development environment bootstrap automation toolkit for OSX
Ruby
31
star
23

vim-open-github

Quickly open your current buffer in GitHub.
Ruby
29
star
24

graphql-query-builder

GraphQL query builder for Java
Java
23
star
25

perf-profile

Profiling C code with Linux perf made easy
Python
19
star
26

wrap-bootstrap-rails

Rails plugin generator for Wrap Bootstrap design templates
Ruby
18
star
27

gosick

Scheme implementation by Go language
Go
18
star
28

hescape-ruby

HTML escape utility for Ruby
Ruby
17
star
29

twitter-auth

Twitter access token generator for CLI
Go
14
star
30

fluent-logger-go

A structured logger for Fluentd in Golang
Go
13
star
31

thunderbolt

Twitter client using Streaming API in Go language
Go
13
star
32

lineprof

Easy-to-use line profiler for Ruby
Ruby
13
star
33

itamae-template

Itamae template generator for roles and cookbooks
Ruby
11
star
34

stackflame

Stackflame provides a simple API to deal with Flamegraph of stackprof
Ruby
9
star
35

itamae-plugin-recipe-docker

Itamae recipe to install docker
Ruby
9
star
36

ghq-cache

Show frequently used repositories first in ghq list
Ruby
9
star
37

github_api-v4-client

A very thin GitHub GraphQL API v4 client
Ruby
7
star
38

clannad

C language compiler
C
7
star
39

go-keybind

Multi-platform terminal key input reader for Go language
Go
7
star
40

action-slack

Notify Slack with incoming webhook for GitHub Actions
TypeScript
6
star
41

tomodachi

Automatic follow back tool with Twitter streaming API
Ruby
5
star
42

twitter

Tiny twitter client library for Go language
Go
5
star
43

dwarftree

A wrapper of objdump --dwarf=info to visualize an object's structure and show code size
Ruby
5
star
44

yjit

Enable YJIT
Ruby
5
star
45

rack-stackprof

Periodically dump StackProf profile result to `tmp` with easy-to-understand filenames
Ruby
4
star
46

go-termios

Go bindings for termios
Go
4
star
47

legacy-dotfiles

Configuration for my client machines
Common Lisp
4
star
48

misc

Miscellaneous scripts and stuff
JavaScript
4
star
49

github-stream

GitHub Events API v3 client for Go language
Go
3
star
50

ajax_render

Rails plugin to simplify your ajax implementation
Ruby
3
star
51

isucon4-qualifier

My answer for ISUCON4 qualifier
Go
3
star
52

sandal

Fault-aware model checker for message passing systems
Go
3
star
53

rockstar

Colorful GitHub user summarizer
Go
3
star
54

mitamae-plugin-resource-deploy_directory

Fork of mitamae-plugin-resource-deploy_revision to deploy directory instead of git repository
Ruby
3
star
55

perf

Use Linux perf for some region of Ruby code easily
Ruby
3
star
56

itamae-plugin-resource-ghq

Itamae resource plugin to manage repositories with ghq
Ruby
3
star
57

itamae-plugin-resource-cask

Itamae resource plugin for homebrew cask
Ruby
2
star
58

chrome-response-time

Chrome extension to show response time on badge
JavaScript
2
star
59

ruby-color

ruby-color foo.rb
Ruby
2
star
60

mitamae-plugin-resource-cron

MItamae plugin to reproduce the behavior of cron resource in Chef
Ruby
2
star
61

sigcdump

Sigdump for C backtrace
Ruby
2
star
62

ruboty

My Ruboty configuration
Ruby
2
star
63

libx11-ruby

Ruby binding of libx11 mostly for xlib
Ruby
2
star
64

xraise

Fast X Window Raiser
Rust
2
star
65

userstream

Twitter UserStream client with OAuth for Go language
Go
2
star
66

mjit-disable

Unofficial gem to disable MJIT dynamically
Ruby
1
star
67

itamae-sandbox

Ruby
1
star
68

PKGBUILDs

PKGBUILDs for Arch Linux
Shell
1
star
69

picturesque

Personal web server for image distribution
Go
1
star
70

changelogger

Local file change logger
Go
1
star
71

ruby-prehistory

A repository generated by https://github.com/yhara/ruby-prehistory
C
1
star
72

ruby-cvs

cvs2git from https://github.com/takahashim/rhg-repository
C
1
star
73

isucon2-ruby

My answer for ISUCON2
Ruby
1
star
74

mitamae-plugin-recipe-rvm

MItamae plugin similar to sous-chefs/rvm
Ruby
1
star
75

GomokuAI

Artificial Intelligence for Gomoku
C++
1
star
76

ruboty-ghibli

A Ruboty plugin
Ruby
1
star
77

mitamae-plugin-recipe-buildpack

MItamae plugin to run heroku-buildpack
Ruby
1
star
78

submarine

Ruby
1
star
79

erb-trim

An ERB extension that supports <%-=
Ruby
1
star
80

erb-indent

ERB with de-indentation
Ruby
1
star
81

vagrant-box-arch

Arch Linux Vagrant box for VirtualBox provider
1
star
82

lambda-gyazo-s3

Gyazo server clone implemented with AWS Lambda and API Gateway
Java
1
star
83

each_with_rank

Rank iterator for Enumerable
Ruby
1
star
84

pr_viewer

Pull requests viewer
Go
1
star