在PostgreSQL中修改了一行不明顯的代碼,把(ANY(ARRAY[...]) 改成 ANY(VALUES(...))),結果查詢時間從20s變為0.2s。最初我們學習使用EXPLAN ANALYZE來優化代碼,到后來,Postgres社區也成為我們學習提升的一個好幫手,付出總會有回報,我們產品的性能也因此得到了極大的提升。
事出有因
我們所開發的產品是Datadog,它是專門為那些編寫和運營大規模應用的團隊、IT運營商提供監控服務的一個平臺,幫助他們把海量的數據轉化為切實可行的計劃、操作方案。而在這周早些時候,我們的許多數據庫所面臨的一個性能問題是在一個較小的表上進行大量的key查詢。這些查詢中的99.9%都是高效靈活的。在極少數實例中,有些數量的性能指標tag查詢是費時的,這些查詢需要花費20s時間。這也就意味著用戶需要在瀏覽器面前花費這么長的時間來等待圖形編輯器做出響應。即使是0.1%,這樣的用戶體驗也顯然糟透了,對此,我們進行了監測,探究為何速度會這么慢。
查詢與計劃
結果令人震驚,罪魁禍首竟然是下面這個簡單的查詢:
SELECt c.key,
c.x_key,
c.tags,
x.name
FROM context c
JOIN x
ON c.x_key = x.key
WHERe c.key = ANY (ARRAY[
15368196
, --
11
,
000
other keys --)])
AND c.x_key =
1
AND c.tags @> ARRAY[E
'blah'
];
X表擁有上千行數據,C表擁有1500萬行數據,這兩個表的“key”列都帶有適當的索引主鍵。簡單地說,它就是一個簡單的主鍵查詢。但有趣地是,隨著key列中記錄的增加,例如在11000行時,我們通過添加EXPLAIN (ANALYZE, BUFFERS)前綴來查看key列的值是否與數組中的值匹配:
Nested Loop (cost=
6923.33
..
11770.59
rows=
1
width=
362
) (actual time=
17128.188
..
22109.283
rows=
10858
loops=
1
)
Buffers: shared hit=
83494
-> Bitmap Heap Scan on context c (cost=
6923.33
..
11762.31
rows=
1
width=
329
) (actual time=
17128.121
..
22031.783
rows=
10858
loops=
1
)
Recheck Cond: ((tags @>
'{blah}'
::text[]) AND (x_key =
1
))
Filter: (key = ANY (
'{15368196,(a lot more keys here)}'
::integer[]))
Buffers: shared hit=
50919
-> BitmapAnd (cost=
6923.33
..
6923.33
rows=
269
width=
0
) (actual time=
132.910
..
132.910
rows=
0
loops=
1
)
Buffers: shared hit=
1342
-> Bitmap Index Scan on context_tags_idx (cost=
0.00
..
1149.61
rows=
15891
width=
0
) (actual time=
64.614
..
64.614
rows=
264777
loops=
1
)
Index Cond: (tags @>
'{blah}'
::text[])
Buffers: shared hit=
401
-> Bitmap Index Scan on context_x_id_source_type_id_idx (cost=
0.00
..
5773.47
rows=
268667
width=
0
) (actual time=
54.648
..
54.648
rows=
267659
loops=
1
)
Index Cond: (x_id =
1
)
Buffers: shared hit=
941
-> Index Scan using x_pkey on x (cost=
0.00
..
8.27
rows=
1
width=
37
) (actual time=
0.003
..
0.004
rows=
1
loops=
10858
)
Index Cond: (x.key =
1
)
Buffers: shared hit=
32575
Total runtime:
22117.417
ms