[英]Improve performance of first query
如果執行以下數據庫(postgres)查詢,則第二次調用要快得多。
我想第一個查詢很慢,因為操作系統(linux)需要從磁盤獲取數據。 第二個查詢受益於文件系統級別和postgres中的緩存。
有沒有辦法優化數據庫,以便在第一次調用時快速獲得結果?
第一次通話 (慢)
foo3_bar_p@BAR-FOO3-Test:~$ psql
foo3_bar_p=# explain analyze SELECT "foo3_beleg"."id", ... FROM "foo3_beleg" WHERE
foo3_bar_p-# (("foo3_beleg"."id" IN (SELECT beleg_id FROM foo3_text where
foo3_bar_p(# content @@ 'footown'::tsquery)) AND "foo3_beleg"."belegart_id" IN
foo3_bar_p(# ('...', ...));
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=75314.58..121963.20 rows=152 width=135) (actual time=27253.451..88462.165 rows=11 loops=1)
-> HashAggregate (cost=75314.58..75366.87 rows=5229 width=4) (actual time=16087.345..16113.988 rows=17671 loops=1)
-> Bitmap Heap Scan on foo3_text (cost=273.72..75254.67 rows=23964 width=4) (actual time=327.653..16026.787 rows=27405 loops=1)
Recheck Cond: (content @@ '''footown'''::tsquery)
-> Bitmap Index Scan on foo3_text_content_idx (cost=0.00..267.73 rows=23964 width=0) (actual time=281.909..281.909 rows=27405 loops=1)
Index Cond: (content @@ '''footown'''::tsquery)
-> Index Scan using foo3_beleg_pkey on foo3_beleg (cost=0.00..8.90 rows=1 width=135) (actual time=4.092..4.092 rows=0 loops=17671)
Index Cond: (id = foo3_text.beleg_id)
Filter: ((belegart_id)::text = ANY ('{...
Rows Removed by Filter: 1
Total runtime: 88462.809 ms
(11 rows)
二次通話 (快速)
Nested Loop (cost=75314.58..121963.20 rows=152 width=135) (actual time=127.569..348.705 rows=11 loops=1)
-> HashAggregate (cost=75314.58..75366.87 rows=5229 width=4) (actual time=114.390..133.131 rows=17671 loops=1)
-> Bitmap Heap Scan on foo3_text (cost=273.72..75254.67 rows=23964 width=4) (actual time=11.961..97.943 rows=27405 loops=1)
Recheck Cond: (content @@ '''footown'''::tsquery)
-> Bitmap Index Scan on foo3_text_content_idx (cost=0.00..267.73 rows=23964 width=0) (actual time=9.226..9.226 rows=27405 loops=1)
Index Cond: (content @@ '''footown'''::tsquery)
-> Index Scan using foo3_beleg_pkey on foo3_beleg (cost=0.00..8.90 rows=1 width=135) (actual time=0.012..0.012 rows=0 loops=17671)
Index Cond: (id = foo3_text.beleg_id)
Filter: ((belegart_id)::text = ANY ('...
Rows Removed by Filter: 1
Total runtime: 348.833 ms
(11 rows)
foo3_text表的表格布局(28M行)
foo3_egs_p=# \d foo3_text
Table "public.foo3_text"
Column | Type | Modifiers
----------+-----------------------+------------------------------------------------------------
id | integer | not null default nextval('foo3_text_id_seq'::regclass)
beleg_id | integer | not null
index_id | character varying(32) | not null
value | text | not null
content | tsvector |
Indexes:
"foo3_text_pkey" PRIMARY KEY, btree (id)
"foo3_text_index_id_2685e3637668d5e7_uniq" UNIQUE CONSTRAINT, btree (index_id, beleg_id)
"foo3_text_beleg_id" btree (beleg_id)
"foo3_text_content_idx" gin (content)
"foo3_text_index_id" btree (index_id)
"foo3_text_index_id_like" btree (index_id varchar_pattern_ops)
Foreign-key constraints:
"beleg_id_refs_id_6e6d40770e71292" FOREIGN KEY (beleg_id) REFERENCES foo3_beleg(id) DEFERRABLE INITIALLY DEFERRED
"index_id_refs_name_341600137465c2f9" FOREIGN KEY (index_id) REFERENCES foo3_index(name) DEFERRABLE INITIALLY DEFERRED
可以進行硬件更改(SSD而不是傳統磁盤)或RAM磁盤。 但也許當前的硬件也可以做得更快。
版本:x86_64-unknown-linux-gnu上的PostgreSQL 9.1.2
如果您需要更多詳細信息,請發表評論。
Postgres為您提供了在運行時查詢執行時進行一些配置的機會,以決定您的I / O操作優先級。
random_page_cost(floating point)
- (參考)是可以幫助你的。 它基本上會設置你的IO / CPU操作比。
更高的值意味着I / O很重要,我有順序磁盤; 和更低的值意味着I / O並不重要,我有隨機訪問磁盤。
默認值為4.0
,如果查詢占用的時間較短,可能需要增加和測試。
不要忘記,您的I / O優先級取決於您的列數,行數。
一個很大的但是; 由於你的指標是btree,你的CPU優先級比I / O優先級上升要快得多。 您基本上可以將復雜性映射到優先級。
CPU Priority = O(log(x))
I/O Priority = O(x)
總而言之,這意味着,如果Postgre價值4.0
將為100k
項,你應該將其設置為(大約) (4.0 * log(100k) * 10M)/(log(10M) * 100k)
為10M
項。
同意Julius但是,如果你只需要來自foo3_beleg的東西,請嘗試使用EXISTS(如果你也粘貼了你的sql它會有所幫助,而不僅僅是你的解釋計划)。
select ...
from foo3_beleg b
where exists
(select 1 from foo_text s where t.beleg_id = b.id)
....
但是,我懷疑你在第一次傳遞時“喚醒”只是你的數據庫將IN子查詢行加載到內存中。 無論如何,這可能會發生,盡管EXISTS通常比IN快得多(如果不包含硬編碼列表則很少需要IN,如果我查看sql則需要黃色標記)。
第一次執行查詢時,postgres將從磁盤加載數據,即使硬盤驅動器也很慢。 第二次運行查詢時,它將從RAM加載以前加載的數據,這顯然更快。
這個問題的解決方案是將關系數據加載到操作系統緩沖區緩存或PostgreSQL緩沖區緩存中:
int8 pg_prewarm(regclass, mode text default 'buffer', fork text default 'main', first_block int8 default null, last_block int8 default null)
:
第一個論點是要預熱的關系。 第二個參數是要使用的預熱方法,如下面進一步討論的; 第三個是要預熱的關系叉,通常是主要的。 第四個參數是第一個預熱的塊編號(NULL被接受為零的同義詞)。 第五個參數是預警的最后一個塊編號(NULL表示通過關系中的最后一個塊預熱)。 返回值是預熱的塊數。
有三種可用的預熱方法。 prefetch向操作系統發出異步預取請求(如果支持),否則拋出錯誤。 read讀取請求的塊范圍; 與prefetch不同,這是同步的,並且在所有平台和構建上都受支持,但可能會更慢。 buffer將請求的塊范圍讀入數據庫緩沖區緩存。
請注意,使用這些方法中的任何一種方法,嘗試預熱更多塊而不是緩存 - 操作系統在使用預取或讀取時使用,或者使用PostgreSQL時使用緩沖區 - 可能會導致編號較低的塊被驅逐,因為讀取的編號較高的塊預警數據也不受高速緩存驅逐的特殊保護,因此其他系統活動可能會在讀取后立即驅逐新預熱的塊; 相反,預熱也可能從緩存中驅逐其他數據。 由於這些原因,預熱通常在啟動時最有用,因為緩存很大程度上是空的。
希望這有幫助!
有時將“WHERE x IN”移動到JOIN中可以顯着提高性能。 試試這個:
SELECT
foo3_beleg.id, ...
FROM
foo3_beleg b INNER JOIN
foo3_text t ON (t.beleg_id = b.id AND t.content @@ 'footown'::tsquery)
WHERE
foo3_beleg.belegart_id IN ('...', ...);
這是一個可重復的實驗來支持我的主張。
我碰巧有一個很大的Postgres數據庫(3000萬行)( http://juliusdavies.ca/2013/j.emse/bertillonage/ ),所以我把它加載到postgres 9.4beta3。
結果令人印象深刻。 子選擇方法慢大約20倍:
time psql myDb < using-in.sql
real 0m17.212s
time psql myDb < using-join.sql
real 0m0.807s
對於那些對復制感興趣的人,以下是我用來測試我的理論的原始SQL查詢。
此查詢使用“SELECT IN”子查詢,並且速度慢20倍(第一次執行時筆記本電腦上的時間為17秒):
-- using-in.sql
SELECT
COUNT(DISTINCT sigsha1re) AS a_intersect_b, infilesha1
FROM
files INNER JOIN sigs ON (files.filesha1 = sigs.filesha1)
WHERE
sigs.sigsha1re IN (
SELECT sigsha1re FROM sigs WHERE sigs.sigsha1re like '0347%'
)
GROUP BY
infilesha1
此查詢將條件移出子查詢並進入加入條件,並且速度提高了20倍(第一次執行時筆記本電腦上的時間為0.8秒)。
-- using-join.sql
SELECT
COUNT(DISTINCT sigsha1re) AS a_intersect_b, infilesha1
FROM
files INNER JOIN sigs ON (
files.filesha1 = sigs.filesha1 AND sigs.sigsha1re like '0347%'
)
GROUP BY
infilesha1
ps如果您對數據庫的用途感到好奇,可以使用它來計算任意jar文件與大約2011年maven存儲庫中的所有jar文件的相似程度。
./query.sh lib/commons-codec-1.5.jar | psql myDb
similarity | a = 39 = commons-codec-1.5.jar (bin2bin)
------------+--------------------------------------------------------------------------------------
1.000 | commons-codec-1.5.jar
0.447 | commons-codec-1.4.jar
0.174 | org.apache.sling.auth.form-1.0.2.jar
0.170 | org.apache.sling.auth.form-1.0.0.jar
0.142 | jbehave-core-3.0-beta-3.jar
0.142 | jbehave-core-3.0-beta-4.jar
0.141 | jbehave-core-3.0-beta-5.jar
0.141 | jbehave-core-3.0-beta-6.jar
0.140 | commons-codec-1.2.jar
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.