Help us understand the problem. What is going on with this article?

ActiveRecordで一意データのみカウントするクエリの速度計測

More than 1 year has passed since last update.

前提

Userモデルが以下の状態

レコード数:105100データあった場合
カラム数:20
インデックス:id
rails consoleで実施

1. User.distinct.count

User.distinct.count
**(38.2ms)**
SELECT DISTINCT COUNT(DISTINCT "user"."id") FROM "users"
=> 105100

一番シンプルな書き方だと思いますが、全件検索してカウントしているで速度が出ません

2. User.uniq.count

User.uniq.count
(36.2ms)
SELECT DISTINCT COUNT(DISTINCT "user"."id") FROM "users"
=> 105100

※ActiveRecord::QueryMethods#uniqはRails5.0より非推奨となっており、次の警告が発生します。

DEPRECATION WARNING: uniq is deprecated and will be removed from Rails 5.1 (use distinct instead)

そのため、以降はActiveRecord::QueryMethods#distinctを使用する様になります。

3. User.count('DISTINCT id')

User.count('DISTINCT id')
(33.3ms)
SELECT COUNT(DISTINCT id) FROM "users"
=> 105100

SQL実行時にインデックス対象のテーブルにアクセスする必要がないので高速になる

4. User.group(:id).pluck(:id).count

User.group(:id).pluck(:id).count
(289.5ms)
SELECT "users"."id" FROM "users" GROUP BY "users"."id"
=> 105100

予想外の遅さ。idにインデックス貼ってるのになぜ??

DBアクセスの結果105100件に対してRubyでカウントしている為、遅くなります。

動作環境

Ruby 2.3.1
Rails 4.2.7
DB:PostgreSQL-9.5

SoarTec-lab
freelance software developer/rails contributor https://contributors.rubyonrails.org/contributors/soartec-lab/commits
classi
学校の先生・生徒・保護者向けのB2B2Cの学習支援Webサービス「Classi(クラッシー)」 を開発・運営している会社です。
https://classi.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away