简体   繁体   English

使用索引的Rails慢速Postgres查询

[英]Rails Slow Postgres Query with Order using Index

I am doing a query on my database of a few million items that gets really slow when I add in an order. 我正在对我的数据库中的几百万个项目进行查询,但是当我添加订单时,查询速度确实变慢。 Here is the code I am calling: 这是我正在调用的代码:

Post.where(source_id: source_ids_array).page(1).per(100).order("position asc, external_created_at desc")

(I am using Kaminari to do pagination) (我正在使用Kaminari进行分页)

Which gives me the following sql: 这给了我以下sql:

Post Load (36537.8ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."source_id" IN (17805, 18768, 20717, 17803, 17804, 18329, 20705, 19075, 19110, 19082, 18328)  ORDER BY position asc, external_created_at desc LIMIT 100 OFFSET 0

However, when I modify the query to just be: 但是,当我将查询修改为:

Post.where(source_id: source_ids_array).page(1).per(100).order("position asc")

I get the following sql: 我得到以下sql:

Post Load (279.6ms)  SELECT  "posts".* FROM "posts"  WHERE "posts"."source_id" IN (17805, 18768, 20717, 17803, 17804, 18329, 20705, 19075, 19110, 19082, 18328)  ORDER BY position asc LIMIT 100 OFFSET 0

Which is insanely faster. 这是疯狂的更快。

My indexes in my schema.db look like this: 我在schema.db中的索引如下所示:

add_index "posts", ["external_created_at"], name: "index_posts_on_external_created_at", using: :btree
add_index "posts", ["position", "external_created_at"], name: "index_posts_on_position_and_external_created_at", using: :btree
add_index "posts", ["position"], name: "index_posts_on_position", using: :btree

How can I go about speeding up this query? 如何加快查询速度?

Edit: here is my EXPLAIN ANALYZE: 编辑:这是我的解释分析:

Limit  (cost=633132.80..633133.05 rows=100 width=891) (actual time=31927.725..31927.751 rows=100 loops=1)
  ->  Sort  (cost=633132.80..635226.42 rows=837446 width=891) (actual time=31927.720..31927.729 rows=100 loops=1)
        Sort Key: "position", external_created_at
        Sort Method: top-N heapsort  Memory: 78kB
        ->  Bitmap Heap Scan on posts  (cost=19878.94..601126.22 rows=837446 width=891) (actual time=487.399..30855.211 rows=858629 loops=1)
              Recheck Cond: (source_id = ANY ('{17805,18768,20717,17803,17804,18329,20705,19075,19110,19082,18328}'::integer[]))
              Rows Removed by Index Recheck: 1050547
              ->  Bitmap Index Scan on index_posts_on_source_id  (cost=0.00..19669.58 rows=837446 width=0) (actual time=485.025..485.025 rows=927175 loops=1)
                    Index Cond: (source_id = ANY ('{17805,18768,20717,17803,17804,18329,20705,19075,19110,19082,18328}'::integer[]))
Total runtime: 31927.998 ms

Although its not very well documented can specify the sort order when creating an index: 尽管其记录不充分,但可以在创建索引时指定排序顺序:

add_index :posts, [:external_created_at, :position], 
    order: { position: :asc, external_created_at: :desc }

If we then run rake db:structure:dump we can see that it creates the following SQL: 如果然后运行rake db:structure:dump我们可以看到它创建了以下SQL:

CREATE INDEX "index_posts_on_external_created_at_and_position" 
 ON "posts" ("external_created_at" DESC, "position" ASC);

Note that we don't need to specify using: :btree since Postgres defaults to using B-tree or the name: . 请注意,我们不需要指定using: :btree因为Postgres默认使用B-tree或name:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM