【发布时间】:2015-12-14 04:40:35
【问题描述】:
我正在对数百万个项目的数据库进行查询,当我添加订单时这些项目变得非常慢。这是我正在调用的代码:
Post.where(source_id: source_ids_array).page(1).per(100).order("position asc, external_created_at desc")
(我用Kaminari做分页)
这给了我以下 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
但是,当我将查询修改为:
Post.where(source_id: source_ids_array).page(1).per(100).order("position asc")
我得到以下 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
这速度快得惊人。
我的 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
如何加快查询速度?
编辑:这是我的解释分析:
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
【问题讨论】:
-
查看
EXPLAIN ANALYZE的每个查询(尤其是超慢查询)的输出会很有帮助。为此,请打开psql或rails db,然后运行 EXPLAIN ANALYZE SELECT "posts".* FROM "posts" WHERE <rest of SQL goes here>。或者,我建议尝试.order("position asc, external_created_at asc")(排序方向相同),看看是否会产生更快的结果(我怀疑由于排序方向不匹配,您的复合索引未使用)。 -
@RobertNubel 您可以在 rails 控制台中使用
Post.where(source_id: source_ids_array).page(1).per(100).order("position asc, external_created_at desc").explain。比复制粘贴到 psql 中简单得多 -
@max 似乎调用
.explain只会导致EXPLAIN SELECT而不是EXPLAIN ANALYZE SELECT -
@goddamnyouryan,你说得对。自多语言以来,ActiveRecord 似乎只有
EXPLAIN。
标签: mysql sql ruby-on-rails postgresql activerecord