一個優化的SQL:
SELECT order_date,
order_source,
SUM(commodity_num) num,
SUM(actual_charge) charge
FROM (
SELECT to_char(oc.create_date, 'yyyyMMdd') AS order_date,
(CASE
WHEN oo.event_type = 'ONLINE_COMMODITY_ORDER' THEN
'線上'
ELSE
'線下'
END) order_source,
oc.commodity_num,
oc.actual_charge actual_charge
FROM ord.ord_commodity_hb_2017 AS oc, ord.ord_order_hb_2017 AS oo
WHERE oc.order_id = oo.order_id
AND oc.op_type = 3 -- 3個值 ,3->5000 大概1/20的數據
AND oc.create_date BETWEEN '2017-02-05' AND '2017-12-07' -- 無用
AND oc.corp_org_id = 106 -- 無用
AND oo.trade_state = 11 -- 3個值 11 --> 71萬行,一半數據
AND oo.event_type IN (values('ONLINE_COMMODITY_ORDER'),
('USER_CANCEL'),
('USER_COMMODITY_UPDATE')) -- 大概1/10 數據
ORDER BY oc.create_date -- 若是業務不強制,最好去掉排序,若是不能去掉,最好等過濾數據量到儘可能小時再排序
) T
GROUP BY order_date, order_source;
View Code
下面默認以postgresql爲例:
1、排序:
1. 儘可能避免
2. 排序的數據量儘可能少,並保證在內存裏完成排序。
(至於具體什麼數據量能在內存中完成排序,不一樣數據庫有不一樣的配置:
oracle是sort_area_size;
postgresql是work_mem (integer),單位是KB,默認值是4MB。
mysql是sort_buffer_size 注意:該參數對應的分配內存是每鏈接獨佔!
)
2、索引:
1. 過濾的數據量比較少,通常來講<20%,應該走索引。20%-40% 可能走索引也可能不走索引。> 40% ,基本不走索引(會全表掃描)
2. 保證值的數據類型和字段數據類型要一直。
3. 對索引的字段進行計算時,必須在運算符右側進行計算。也就是 to_char(oc.create_date, 'yyyyMMdd')是沒用的
4. 表字段之間關聯,儘可能給相關字段上添加索引。
5. 複合索引,聽從最左前綴的原則,即最左優先。(單獨右側字段查詢沒有索引的)
3、鏈接查詢方式:
一、hash join
放內存裏進行關聯。
適用於結果集比較大的狀況。
好比都是200000數據
二、nest loop
從結果1 逐行取出,而後與結果集2進行匹配。
適用於兩個結果集,其中一個數據量遠大於另一個時。
結果集一:1000
結果集二:1000000
4、多表聯查時:
在多表聯查時,須要考慮鏈接順序問題。
一、當postgresql中進行查詢時,若是多表是經過逗號,而不是join鏈接,那麼鏈接順序是多表的笛卡爾積中取最優的。若是有太多輸入的表, PostgreSQL規劃器將從窮舉搜索切換爲基因機率搜索,以減小可能性數目(樣本空間)。基因搜索花的時間少, 可是並不必定能找到最好的規劃。
二、對於JOIN,
LEFT JOIN / RIGHT JOIN 會必定程度上指定鏈接順序,可是仍是會在某種程度上從新排列:
FULL JOIN 徹底強制鏈接順序。
若是要強制規劃器遵循準確的JOIN鏈接順序,咱們能夠把運行時參數join_collapse_limit設置爲 1
5、PostgreSQL提供了一些性能調優的功能:
優化思路:
0、爲每一個表執行 ANALYZE <table>。而後分析 EXPLAIN (ANALYZE,
BUFFERS) sql。
一、對於多表查詢,查看每張表數據,而後改進鏈接順序。
二、先查找那部分是重點語句,好比上面SQL,外面的嵌套層對於優化來講沒有意義,能夠去掉。
三、查看語句中,where等條件子句,每一個字段能過濾的效率。找出可優化處。
好比oc.order_id = oo.order_id是關聯條件,須要加索引
oc.op_type = 3 能過濾出1/20的數據,
oo.event_type IN (...) 能過濾出1/10的數據,
這兩個是優化的重點,也就是實現確保op_type與event_type已經加了索引,其次確保索引用到了。
優化方案:
a) 總體優化:
一、使用EXPLAIN
EXPLAIN命令能夠查看執行計劃,這個方法是咱們最主要的調試工具。
二、及時更新執行計劃中使用的統計信息
因爲統計信息不是每次操做數據庫都進行更新的,通常是在 VACUUM 、 ANALYZE 、 CREATE INDEX等DDL執行的時候會更新統計信息,
所以執行計劃所用的統計信息頗有可能比較舊。 這樣執行計劃的分析結果可能偏差會變大。
如下是表tenk1的相關的一部分統計信息。
SELECT relname, relkind, reltuples, relpages
FROM pg_class
WHERE relname LIKE 'tenk1%';
relname | relkind | reltuples | relpages
----------------------+---------+-----------+----------
tenk1 | r | 10000 | 358
tenk1_hundred | i | 10000 | 30
tenk1_thous_tenthous | i | 10000 | 30
tenk1_unique1 | i | 10000 | 30
tenk1_unique2 | i | 10000 | 30
(5 rows)
其中 relkind是類型,r是自身表,i是索引index;reltuples是項目數;relpages是所佔硬盤的塊數。
估計成本經過
(磁盤頁面讀取【
relpages
】*seq_page_cost)+(行掃描【
reltuples
】*cpu_tuple_cost)計算。
默認狀況下, seq_page_cost是1.0,cpu_tuple_cost是0.01。
名字 |
類型 |
描述 |
relpages |
int4 |
以頁(大小爲BLCKSZ)的此表在磁盤上的形式的大小。 它只是規劃器用的一個近似值,是由VACUUM,ANALYZE 和幾個 DDL 命令,好比CREATE INDEX更新。 |
reltuples |
float4 |
表中行的數目。只是規劃器使用的一個估計值,由VACUUM,ANALYZE 和幾個 DDL 命令,好比CREATE INDEX更新。 |
三、使用臨時表(with)
對於數據量大,且沒法有效優化時,可使用臨時表來過濾數據,下降數據數量級。
四、對於會影響結果的分析,可使用 begin;...rollback;來回滾。
b) 查詢優化:
一、明確用join來關聯表,確保鏈接順序
通常寫法:SELECT * FROM a, b, c WHERE a.id = b.id AND b.ref = c.id;
若是明確用join的話,執行時候執行計劃相對容易控制一些。
例子:
SELECT * FROM a CROSS JOIN b CROSS JOIN c WHERE a.id = b.id AND b.ref = c.id;
SELECT * FROM a JOIN (b JOIN c ON (b.ref = c.id)) ON (a.id = b.id);
c) 插入更新優化
一、關閉自動提交(autocommit=false)
若是有多條數據庫插入或更新等,最好關閉自動提交,這樣能提升效率
二、屢次插入數據用copy命令更高效
咱們有的處理中要對同一張表執行不少次insert操做。這個時候咱們用copy命令更有效率。由於insert一次,其相關的index都要作一次,比較花費時間。
三、臨時刪除index【具體能夠查看Navicat表數據生成sql的語句,就是先刪再建的】
有時候咱們在備份和從新導入數據的時候,若是數據量很大的話,要好幾個小時才能完成。這個時候能夠先把index刪除掉。導入後再建index。
四、外鍵關聯的刪除
若是表的有外鍵的話,每次操做都沒去check外鍵整合性。所以比較慢。數據導入後再創建外鍵也是一種選擇。
d) 修改參數:
選項 |
默認值 |
說明 |
是否優化 |
緣由 |
max_connections |
100 |
容許客戶端鏈接的最大數目 |
否 |
由於在測試的過程當中,100個鏈接已經足夠 |
fsync |
on |
強制把數據同步更新到磁盤 |
是 |
由於系統的IO壓力很大,爲了更好的測試其餘配置的影響,把改參數改成off |
shared_buffers |
24MB |
決定有多少內存能夠被PostgreSQL用於緩存數據(推薦內存的1/4) |
是 |
在IO壓力很大的狀況下,提升該值能夠減小IO |
work_mem |
1MB |
使內部排序和一些複雜的查詢都在這個buffer中完成 |
是 |
有助提升排序等操做的速度,而且減低IO |
effective_cache_size |
128MB |
優化器假設一個查詢能夠用的最大內存,和shared_buffers無關(推薦內存的1/2) |
是 |
設置稍大,優化器更傾向使用索引掃描而不是順序掃描 |
maintenance_work_mem |
16MB |
這裏定義的內存只是被VACUUM等耗費資源較多的命令調用時使用 |
是 |
把該值調大,能加快命令的執行 |
wal_buffer |
768kB |
日誌緩存區的大小 |
是 |
能夠下降IO,若是趕上比較多的併發短事務,應該和commit_delay一塊兒用 |
checkpoint_segments |
3 |
設置wal log的最大數量數(一個log的大小爲16M) |
是 |
默認的48M的緩存是一個嚴重的瓶頸,基本上都要設置爲10以上 |
checkpoint_completion_target |
0.5 |
表示checkpoint的完成時間要在兩個checkpoint間隔時間的N%內完成 |
是 |
能下降平均寫入的開銷 |
commit_delay |
0 |
事務提交後,日誌寫到wal log上到wal_buffer寫入到磁盤的時間間隔。須要配合commit_sibling |
是 |
可以一次寫入多個事務,減小IO,提升性能 |
commit_siblings |
5 |
設置觸發commit_delay的併發事務數,根據併發事務多少來配置 |
是 |
減小IO,提升性能 |
autovacuum_naptime |
1min |
下一次vacuum任務的時間 |
是 |
提升這個間隔時間,使他不是太頻繁 |
autovacuum_analyze_threshold |
50 |
與autovacuum_analyze_scale_factor配合使用,來決定是否analyze |
是 |
使analyze的頻率符合實際 |
autovacuum_analyze_scale_factor |
0.1 |
當update,insert,delete的tuples數量超過autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold時,進行analyze。 |
是 |
使analyze的頻率符合實際 |
下面介紹幾個我認爲重要的:
一、增長maintenance_work_mem參數大小
增長這個參數能夠提高CREATE INDEX和ALTER TABLE ADD FOREIGN KEY的執行效率。
二、增長checkpoint_segments參數的大小
增長這個參數能夠提高大量數據導入時候的速度。
三、設置archive_mode無效
這個參數設置爲無效的時候,可以提高如下的操做的速度
・CREATE TABLE AS SELECT
・CREATE INDEX
・ALTER TABLE SET TABLESPACE
・CLUSTER等。
四、autovacuum相關參數
autovacuum:默認爲on,表示是否開起autovacuum。默認開起。特別的,當須要凍結xid時,儘管此值爲off,PG也會進行vacuum。
autovacuum_naptime
:下一次vacuum的時間,默認1min。 這個naptime會被vacuum launcher分配到每一個DB上。autovacuum_naptime/num of db。
log_autovacuum_min_duration:記錄autovacuum動做到日誌文件,當vacuum動做超過此值時。 「-1」表示不記錄。「0」表示每次都記錄。
autovacuum_max_workers:最大同時運行的worker數量,不包含launcher自己。
autovacuum_work_mem
:每一個worker可以使用的最大內存數。
autovacuum_vacuum_threshold
:默認50。與autovacuum_vacuum_scale_factor配合使用, autovacuum_vacuum_scale_factor默認值爲20%。當update,delete的tuples數量超過autovacuum_vacuum_scale_factor*table_size+autovacuum_vacuum_threshold時,進行vacuum。若是要使vacuum工做勤奮點,則將此值改小。
autovacuum_analyze_threshold
:默認50。與autovacuum_analyze_scale_factor配合使用。
autovacuum_analyze_scale_factor
:
默認10%。當update,insert,delete的tuples數量超過autovacuum_analyze_scale_factor*table_size+autovacuum_analyze_threshold時,進行analyze。
autovacuum_freeze_max_age:
200 million。離下一次進行xid凍結的最大事務數。
autovacuum_multixact_freeze_max_age:400 million。離下一次進行xid凍結的最大事務數。
autovacuum_vacuum_cost_delay
:若是爲-1,取vacuum_cost_delay值。
autovacuum_vacuum_cost_limit
:若是爲-1,到vacuum_cost_limit的值,這個值是全部worker的累加值。