天天看點

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

digoal

2016-10-08

postgresql , 9.6 , 核心優化 , sort , replacement selection , quciksort

排序是比較常見的業務需求,為了降低排序的cpu開銷,通常會使用索引來滿足排序的需求。

但是并不是所有的query都能使用索引排序,或者說使用索引排序就一定高效。

例如帶過濾條件的query,過濾完之後再根據某些字段或表達式排序。這種query的排序不一定能用上索引。

當需要實時排序時,postgresql資料庫怎麼處理的呢?

postgresql根據排序的資料量, work_mem的大小 選擇合适的排序算法。

排序算法參考

<a href="https://en.wikipedia.org/wiki/sorting_algorithm">https://en.wikipedia.org/wiki/sorting_algorithm</a>

包括每種排序算法的最小開銷,最大開銷,平均開銷,記憶體需求,穩定性等。

1. 當需要排序的資料量較小,可以在work_mem參數設定的記憶體值内完成時,會使用qsort排序,這個9.6并沒有改進,與以前一樣。

quicksort算法參考

<a href="https://en.wikipedia.org/wiki/quicksort">https://en.wikipedia.org/wiki/quicksort</a>

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

2. 當需要排序的資料量較大,無法在work_mem參數設定的記憶體值内完成時,會使用臨時檔案以及标準的external sort算法。

2.1 postgresql 9.6以前的版本external sort使用heapsort算法(selection排序的變種)。

參考1 knuth volume 3, algorithm 5.2.3h

<a href="https://books.google.com.hk/books?id=cyulbaaaqbaj&amp;pg=pa757&amp;lpg=pa757&amp;dq=knuth++5.2.3h&amp;source=bl&amp;ots=kjcxoiqs5g&amp;sig=s0gebvmp_bb0uqrgxshzfrdbyju&amp;hl=zh-cn&amp;sa=x&amp;ved=0ahukewiy8tsj0czpahxe3ymkhe3ydr0q6aeiojae#v=onepage&amp;q&amp;f=false">https://books.google.com.hk/books?id=cyulbaaaqbaj&amp;pg=pa757&amp;lpg=pa757&amp;dq=knuth++5.2.3h&amp;source=bl&amp;ots=kjcxoiqs5g&amp;sig=s0gebvmp_bb0uqrgxshzfrdbyju&amp;hl=zh-cn&amp;sa=x&amp;ved=0ahukewiy8tsj0czpahxe3ymkhe3ydr0q6aeiojae#v=onepage&amp;q&amp;f=false</a>

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

參考2 heapsort

<a href="https://en.wikipedia.org/wiki/sorting_algorithm#heapsort">https://en.wikipedia.org/wiki/sorting_algorithm#heapsort</a>

heapsort原理如圖

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

selection sort原理如圖,對排序順序與實際順序一緻的資料效果很不錯,但是對離散資料效果不好。

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

2.2 postgresql 9.6 的改進,隻對頭部掃描的n條記錄使用selection排序,提升随機資料的排序效率,通過參數work_mem與replacement_sort_tuples限制n。随後的資料使用分批的quicksort和merge sort得到結果。

決定使用replacement selection

replacement_sort_tuples建議設定的值與cpu cache size有關,cpu cache size越大,可以調大這個值。 否則建議不要修改它。

3. 分批使用knuth's algorithm 5.4.2d, 在postgresql的logtape.c中實作。

4. merge sort, 參考

<a href="https://en.wikipedia.org/wiki/polyphase_merge_sort">https://en.wikipedia.org/wiki/polyphase_merge_sort</a>

5. tuplesort說明。

src/backend/utils/sort/tuplesort.c

當work_mem不足完成記憶體排序時,會選擇external sort或external merge。

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

根據資料量的大小,分階段排序,合并。

可以通過trace_sort觀察,後面會有例子。

explain 時可能看到的一些資訊

前面已經描述過了,以9.5作為比較,9.6不同的地方,如下圖

PostgreSQL 9.6 核心優化 - sort性能增強(batch化quicksort代替replacement selection when work_mem small)

9.5每個小的batch(tape)都是使用replacement selection的排序算法。

而9.6則是通過replacement_sort_tuples配置,初次掃描的replacement_sort_tuples條記錄使用replacement selection算法(以裝下一個work_mem機關為止,是以可能實際的replacement selection記錄數小于replacement_sort_tuples的設定),超出的tuples使用quicksort。

使用trace_sort也可以跟蹤到兩個版本的排序算法差異。

replacement selection 是替代排序,對于亂序的資料,排序的效率很差,因為得不停的替換,而對于實體順序與邏輯順序一緻(是順序一緻,倒序一緻不算)的效果則很不錯。

亂序資料quick sort效率比replacement selection效率高,适用範圍廣泛。

9.6的排序改進說明如下

<a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0711803775a37e0bf39d7efdd1e34d9d7e640ea1">https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0711803775a37e0bf39d7efdd1e34d9d7e640ea1</a>

1. 1000萬亂序資料排序

1.1 9.5

1000萬随機資料9.5排序約耗時9562-995=8567毫秒

1.2 9.6

1000萬随機資料9.6排序約耗時7944-899=7045毫秒

如果不想讓9.6使用replacement selection,把replacement_sort_tuples設定為0即可。

如果要少點batch,可以設定更大的work_mem,但是不要超過表的大小,否則會使用inmemory排序,那就看不到external sort或external merge的效果了。

9.5

9.6

2. 1000萬順序資料排序

2.1 9.5

1000萬順序資料9.5排序約耗時5717-901=4816毫秒

2.2 9.6

1000萬順序資料9.6排序約耗時5903-924=4979毫秒

通常不建議修改replacement_sort_tuples的值,與cpu cache比對。

<a href="https://www.postgresql.org/docs/9.6/static/runtime-config-resource.html#runtime-config-resource-memory">https://www.postgresql.org/docs/9.6/static/runtime-config-resource.html#runtime-config-resource-memory</a>

<a href="https://en.wikipedia.org/wiki/external_sorting">https://en.wikipedia.org/wiki/external_sorting</a>

<a href="https://en.wikipedia.org/wiki/selection_sort">https://en.wikipedia.org/wiki/selection_sort</a>

<a href="http://info.flagcounter.com/h9v1">count</a>

繼續閱讀