2015-12-14 40 views
1

我在我的數據庫上查詢數百萬個項目,當我添加訂單時變得非常慢。下面是我打電話的代碼:Rails Slow Postgres查詢使用索引的順序

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

(我用雷做分頁)

這給了我下面的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 

我怎麼能去加快此查詢?

編輯:這裏是我的EXPLAIN分析一下:

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 
+1

這將是有益的,看看的輸出'EXPLAIN ANALYZE'對於每個查詢(尤其是超慢一個)的。要做到這一點,打開'psql'或'rails db',並運行'EXPLAIN ANALYZE SELECT「posts」。* FROM「posts」WHERE <其餘的SQL去這裏>。或者,我會建議嘗試'.order(「位置asc,external_created_at asc」)'(排序方向相同),看看是否會產生更快的結果(我懷疑*你的複合索引沒有使用到期到不匹配的排序方向)。 –

+2

@RobertNubel你可以在rails控制檯中使用'Post.where(source_id:source_ids_array).page(1).per(100).order(「position asc,external_created_at desc」)。比複製到psql – max

+0

@max更簡單,似乎調用'.explain'只會導致'EXPLAIN SELECT'而不是'EXPLAIN ANALYSE SELECT'。 – goddamnyouryan

回答

2

雖然它沒有很好的記錄可以指定創建索引時的排序順序:

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

如果我們再運行rake db:structure:dump我們可以看到它會創建以下SQL:

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

請注意,我們不需要d指定using: :btree,因爲Postgres默認使用B-tree或name:

+1

我希望這是有幫助的。我在古老的iMac上打字,插入有意義數量的記錄需要花費很長時間,所以我無法驗證是否使用了索引。我建議你用pgbackups鏡像數據庫,並測試如何用'.explain'調整索引和查詢。 – max

+0

我試着添加這個,它似乎加快了一點,但它仍然很慢。我編輯了我的問題以添加EXPLAIN ANALYZE。 – goddamnyouryan

+1

好吧,我對如何進一步優化它感到茫然。你將不得不等待Postgres嚮導出現尖尖的帽子。 – max