<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                PostgreSQL內核中引入了一個很有意思的插件,pg_prewarm。它可以用于在系統重啟時,手動加載經常訪問的表到操作系統的cache或PG的shared buffer,從而減少檢查系統重啟對應用的影響。這個插件是這個通過這個[patch](http://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=c32afe53c2e87a56e2ff930798a5588db0f7a516)加入PG內核的。 pg_prewarm的開發者在設計pg_prewarm時,把它設計成一個執行單一任務的工具,盡求簡單,所以我們看到的pg_prearm功能和實現都非常簡單。下面我們對它進行性能實測并分析一下它的實現。 **基本信息** 利用下面的語句可以創建此插件: ~~~ create EXTENSION pg_prewarm; ~~~ 實際上,創建插件的過程只是用下面的語句創建了pg_prewarm函數。這個函數是此插件提供的唯一函數: ~~~ CREATE FUNCTION pg_prewarm(regclass, mode text default 'buffer', fork text default 'main', first_block int8 default null, last_block int8 default null) RETURNS int8 AS 'MODULE_PATHNAME', 'pg_prewarm' LANGUAGE C ~~~ 函數的第一個參數是要做prewarm的表名,第二個參數是prewarm的模式(prefetch模式表示異步預取到操作系統cache;read表示同步預取;buffer則表示同步讀入到PG的shared buffer),第三個參數是relation fork的類型(一般用main,其他類型有visibilitymap和fsm,參見[[1]](https://github.com/postgres/postgres/blob/4baaf863eca5412e07a8441b3b7e7482b7a8b21a/src/include/common/relpath.h)[[2]](https://github.com/postgres/postgres/blob/b819dd7cb55aed1d607cef36b0ecd1a0642872b2/src/backend/storage/smgr/README)),最后兩個參數是開始和結束的block number(一個表的block number從0開始,block總數可以通過pg_class系統表的relpages字段獲得)。 **性能實測** 再來看看,這個prewarm性能上能達到多大效果。我們先將PG的shared buffer設為2G,OS總的memory有7G。然后創建下面的大小近1G的表test: ~~~ pgbench=# \d test Table "public.test" Column | Type | Modifiers --------+---------------+----------- name | character(20) | ~~~ ~~~ pgbench=# SELECT pg_size_pretty(pg_total_relation_size('test')); pg_size_pretty ---------------- 995 MB ~~~ 在每次都清掉操作系統cache和PG的shared buffer的情況下,分別測試下面幾種場景: 1)不進行pg_prewarm的情況: ~~~ pgbench=# explain analyze select count(*) from test; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=377389.91..377389.92 rows=1 width=0) (actual time=22270.304..22270.304 rows=1 loops=1) -> Seq Scan on test (cost=0.00..327389.73 rows=20000073 width=0) (actual time=0.699..18287.199 rows=20000002 loops=1) Planning time: 0.134 ms Execution time: 22270.383 ms ~~~ 可以看到,近1G的表,全表掃描一遍,耗時22秒多。 2)下面我們先做read這種模式的prewarm,test表的數據被同步讀入操作系統cache(pg_prewarm返回的是處理的block數目,此處我們沒指定block number,也就是讀入test的所有block),然后再做全表掃: ~~~ pgbench=# select pg_prewarm('test', 'read', 'main'); pg_prewarm ------------ 127389 ~~~ ~~~ pgbench=# explain analyze select count(*) from test; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=377389.90..377389.91 rows=1 width=0) (actual time=8577.767..8577.767 rows=1 loops=1) -> Seq Scan on test (cost=0.00..327389.72 rows=20000072 width=0) (actual time=0.086..4716.444 rows=20000002 loops=1) Planning time: 0.049 ms Execution time: 8577.831 ms ~~~ 時間降至8秒多!這時反復執行全表掃描,時間穩定在8秒多。 3)再嘗試buffer模式: ~~~ pgbench=# select pg_prewarm('test', 'buffer', 'main'); pg_prewarm ------------ 127389 ~~~ ~~~ pgbench=# explain analyze select count(*) from test; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=377389.90..377389.91 rows=1 width=0) (actual time=8214.277..8214.277 rows=1 loops=1) -> Seq Scan on test (cost=0.00..327389.72 rows=20000072 width=0) (actual time=0.015..4250.300 rows=20000002 loops=1) Planning time: 0.049 ms Execution time: 8214.340 ms ~~~ 比read模式時間略少,但相差不大。可見,如果操作系統的cache夠大,數據取到OS cache還是shared buffer對執行時間影響不大(在不考慮其他應用影響PG的情況下)。 4)最后嘗試prefetch模式,即異步預取。這里,我們有意在pg_prewarm返回后,立即執行全表查詢。這樣在執行全表查詢時,可能之前的預取還沒完成,從而使全表查詢和預取并發進行,縮短了總的響應時間: ~~~ explain analyze select pg_prewarm('test', 'prefetch', 'main'); QUERY PLAN ------------------------------------------------------------------------------------------ Result (cost=0.00..0.01 rows=1 width=0) (actual time=1011.338..1011.339 rows=1 loops=1) Planning time: 0.124 ms Execution time: 1011.402 ms ~~~ ~~~ explain analyze select count(*) from test; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=377389.90..377389.91 rows=1 width=0) (actual time=8420.652..8420.652 rows=1 loops=1) -> Seq Scan on test (cost=0.00..327389.72 rows=20000072 width=0) (actual time=0.065..4583.200 rows=20000002 loops=1) Planning time: 0.344 ms Execution time: 8420.723 ms ~~~ 可以看到,總的完成時間是9秒多,使用pg_prewarm做預取大大縮短了總時間。因此在進行全表掃描前,做一次異步的prewarm,不失為一種優化全表查詢的方法。 **實現** pg_prewarm的代碼只有一個pg_prewarm.c文件。可以看出,prefetch模式下,對于表的每個block,調用一次PrefetchBuffer,后面的調用為: ~~~ PrefetchBuffer -> smgrprefetch -> mdprefetch -> FilePrefetch -> posix_fadvise(POSIX_FADV_WILLNEED) ~~~ 可見,它是最終調用posix_fadvise,把讀請求交給操作系統,然后返回,實現的異步讀取。 而在read和buffer模式(調用邏輯分別如下)中,最終都調用了系統調用read,來實現同步讀入OS cache和shared buffer的(注意buffer模式實際上是先讀入OS cache,再拷貝到shared buffer): ~~~ read模式:smgrread -> mdread -> FileRead -> read ~~~ ~~~ buffer模式:ReadBufferExtended -> ReadBuffer_common -> smgrread -> mdread -> FileRead -> read ~~~ **問題** 可能有人比較疑惑:執行1次select * from 不就可以將表的數據讀入shared buffer和OS cache而實現預熱了嗎?豈不是比做這樣一個插件更簡單?實際上,對于較大的表(大小超過shared buff的1/4),進行全表掃描時,PG認為沒必要為這種操作使用所有shared buffer,只會讓其使用很少的一部分buffer,一般只有幾百K,詳細描述可以參見[關于BAS_BULKREAD策略的代碼](https://github.com/postgres/postgres/blob/4baaf863eca5412e07a8441b3b7e7482b7a8b21a/src/include/storage/bufmgr.h)和[README](https://github.com/postgres/postgres/tree/17792bfc5b62f42a9dfbd2ac408e7e71c239330a/src/backend/storage/buffer))。所以,預熱大表是不能用一個查詢直接實現的,而pg_prewarm正是在這方面大大方便了用戶。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看