數(shù)據(jù)庫經(jīng)常要做一些查詢與插入,但是如果查詢和插入的數(shù)據(jù)量過大的時候就會引發(fā)數(shù)據(jù)庫性能問題,降低數(shù)據(jù)庫工作效率。因此性能調(diào)優(yōu)是大家在工作中都能夠預見的問題,大到世界五百強的核心系統(tǒng),小到超市的庫存系統(tǒng),幾乎都會有要調(diào)優(yōu)的時候。面對形形色色的系統(tǒng),林林總總的需求,調(diào)優(yōu)的手段也是豐富多彩。
1.盡量使語句符合查詢優(yōu)化器的規(guī)則避免全表掃描而使用索引查詢
2.避免頻繁創(chuàng)建和刪除臨時表,以減少系統(tǒng)表資源的消耗。
3.盡量避免向客戶端返回大數(shù)據(jù)量,若數(shù)據(jù)量過大,應該考慮相應需求是否合理。?
4.建立高效的索引
SQL語句的Select部分只寫必要的列;盡量將In子查詢重寫為Exists子查詢;
去除在謂詞列上編寫的任何數(shù)學運算;盡可能不用Distinct;
由于優(yōu)化工具處理“或”邏輯可能有問題,所以盡量采用其他方式重寫;
確保所處理的表中數(shù)據(jù)分布和其他統(tǒng)計信息正確,并反映當前狀況;盡可能用UNION ALL取代UNION;
盡可能減少DB2的SQL請求;盡量將區(qū)間謂詞重寫為Between謂詞;不要只是為了排序而選擇某一列;
我目前所在的系統(tǒng)就是這么一個有實時插入又需要大數(shù)據(jù)的查詢的一個系統(tǒng)。
采用了如下手段:
1,當天的記錄會放在一個獨立的表中.主要是針對實時的插入的記錄,記錄不要太多以免插入的時候維護索引的開銷穩(wěn)定在一個范圍內(nèi)。
2,歷史的記錄會按天分區(qū)的形式保存在歷史表中。這個表一天只會批量的插入一次數(shù)據(jù)(用的是分區(qū)交換的方法)。
3,分區(qū)的索引對我的業(yè)務性能不好,因為要跨天 查詢。歷史查詢最長時間段是一個月的時間,如果按照一個月一個分區(qū)的話,一個分區(qū)差不多是一個億的記錄,
就算是按月分區(qū)的話,再創(chuàng)建分區(qū)的本地索引,如果是時間段跨了月份的話估計分區(qū)的本地索引性能估計也不行。
4,后來采用一個方案,DB層上面再放了一個緩沖層,就是我最近在測試的Timesten關系型內(nèi)存數(shù)據(jù)庫,按照時間的老化策略緩沖一個月的數(shù)據(jù)。具體不展開說了。涉及的內(nèi)容很多。
只是對于這個系統(tǒng),我總結一下有以下需要注意的地方:
1,對于一個系統(tǒng)來說,如果查詢性能反應不好的話,第一個調(diào)整的地方是思考業(yè)務的需求是否是合理的?
一個查詢既要分頁獲取前面一頁或者幾頁的數(shù)據(jù),又要根據(jù)條件獲取總的記錄數(shù),如果符合的記錄總數(shù)是上億條的話,感覺就是一個不合理的要求。
2,市場需求調(diào)研人員業(yè)務水平根本不合格。
3,前臺開發(fā)人員寫的SQL差,根本沒有調(diào)優(yōu)的基本概念,術業(yè)有專攻啊。
4,如果業(yè)務需求合理,SQL的調(diào)整無非是從執(zhí)行計劃開始,如果是ORACLE10g,開了cbo,可以用 SQL優(yōu)化器 (SQL Tuning Advisor :STA)
分析你的sql。
5,最近的nosq和海量分布式的數(shù)據(jù)庫概念很熱。公司也在考慮HBASE了。
分區(qū),
讀寫分離。
細節(jié)的優(yōu)化手段大家都說了很多,我說些幾個粗略的方面:
1.使用分區(qū)表
2.并行查詢
3.定期的數(shù)據(jù)信息采集
4.可以考慮使用sql hint(生產(chǎn)庫上我個人認為還是少指定 HINT,可以考慮用 SQL_PROFILE固定執(zhí)行計劃)
對于大數(shù)據(jù)量的處理,我通常采用如下方法:
一、對于大數(shù)據(jù)存儲的處理(以下是假設硬件指標合格的情況)
(1)對大表進行分區(qū),根據(jù)不同的業(yè)務以及數(shù)據(jù)特征,采用不同的分區(qū)方法。比如,銷售,可以考慮采用間隔分區(qū)技術,多分公司或是多部門,可以考慮采用列表分區(qū)或是上述的組合分區(qū)等。
(2)如果硬件具備,對于大表進行分離存儲,從而減少磁盤爭用。
(3)對歷史數(shù)據(jù)進行定期的歸檔處理。比如,銷售的區(qū)間分區(qū),可以采用表與分區(qū)交換的技術去處理。對于含有復雜的業(yè)務的數(shù)據(jù)表的歸檔,采用PL/SQL腳本與后臺作業(yè)定時完成。
二、對于查詢的處理(以下是基于成本優(yōu)化器的情況)
對于查詢,優(yōu)化的方法通常會多一些,但是也是最頻繁調(diào)整的一塊內(nèi)容。通常,我從如下這幾個方面來進行考慮并調(diào)優(yōu).
(1)對于SQL本身的編寫是否合理。比如基礎寫法與高級寫法之間的配合,在滿足業(yè)務要求的基礎上,做到盡量減少表的訪問。
(2)索引的創(chuàng)建是否合理,優(yōu)化器是否選擇了較正確的索引。在不同的業(yè)務場景下,B*樹索引與位圖索引的相互配合是否合理等。
(3)監(jiān)控系統(tǒng)中產(chǎn)生的爭用,根據(jù)產(chǎn)生的不同的閂或鎖,對SQL或是業(yè)務處理邏輯進行調(diào)整。
(4)如果有必要,根據(jù)當前系統(tǒng)的負載與硬件本身的支持,對PGA,SGA進行一個分配,使之更為合理。
(5)如果有必要,在優(yōu)化器參數(shù)進行一個調(diào)整。
(6)采用并行處理。
三、對數(shù)據(jù)插入的處理
這是考慮問題當中最薄弱的一塊內(nèi)容,一般不作必要的優(yōu)化處理,但有如下一些技巧:
(1)對于大數(shù)據(jù)量的表與表之間的插入,可以采用并行,直接路徑、最小化日志。
(2)如果必要,對表本身參數(shù)進行一個修改,如freelist。
(3)如果是同數(shù)據(jù)源多目標的插入,可以采用多表插入技術。
(4)如果可以,盡量使用INSERT INTO SELECT,CREATE TABLE AS SELECT方法。
如果在前期需求調(diào)研,設計階段就做好了工作。那么后面的性能優(yōu)化問題麻煩就可以少很多。
當然通常由于各種原因,往往前期做不到那么好。
那么找到問題,發(fā)現(xiàn)問題,解決問題,通常
1. 通過工具來定位問題,例如選擇用10046 TRACE 工具包來實現(xiàn)
2. 找到問題所在以后去理解需求,探索是否能少做事完成需求(選擇用索引來替代全表掃描,從而減少訪問路徑);?
3. 去思考需求背后的真正需求,例如是否可以用UNION ALL取代UNION ,避免不必要的排序引起資源消耗。?
4. 去分析資源如何合理應用 (在系統(tǒng)空閑時使用并行技術)。
5.診斷索引方面的問題。例如是否由于錯誤的優(yōu)化器統(tǒng)計信息導致執(zhí)行了不正確的執(zhí)行計劃。
數(shù)據(jù)庫表進行插入、查詢操作當數(shù)據(jù)達到百萬甚至千萬條級別的時候, 這一切似乎變得相當困難。幾經(jīng)折騰,總算完成了任務。在此做些簡單的小結,不足之處,還望高手們幫忙補充補充!?
1、避免使用Hibernate框架?
Hibernate用起來雖然方便,但對于海量數(shù)據(jù)的操作顯得力不從心。?
關于插入:?
試過用Hibernate一次性進行5萬條左右數(shù)據(jù)的插入,若ID使用sequence方式生成,Hibernate將分5萬次從數(shù)據(jù)庫取得 5萬個sequence,構造成相應對象后,再分五萬次將數(shù)據(jù)保存到數(shù)據(jù)庫?;宋沂昼姇r間。主要的時間不是花在插入上,而是花在5萬次從數(shù)據(jù)庫取 sequence上,弄得我相當郁悶。雖然后來把ID生成方式改成increase解決了問題,但還是對那十分鐘的等待心有余悸。?
關于查詢:?
Hibernate對數(shù)據(jù)庫查詢的主要思想還是面向?qū)ο蟮?,這將使許多我們不需要查詢的數(shù)據(jù)占用了大量的系統(tǒng)資源(包括數(shù)據(jù)庫資源和本地資 源)。由于對Hibernate的偏愛,本著不拋棄、不放棄的作風,做了包括配SQL,改進SQL等等的相當多的嘗試,可都以失敗告終,不得不忍痛割愛 了。?
2、寫查詢語句時,要把查詢的字段一一列出?
查詢時不要使用類似select * from x_table的語句,要盡量使用select id,name from x_table,以避免查詢出不需要的數(shù)據(jù)浪費資源。對于海量數(shù)據(jù)而言,一個字段所占用的資源和查詢時間是相當可觀的。?
3、減少不必要的查詢條件?
當我們在做查詢時,常常是前臺提交一個查詢表單到后臺,后臺解析這個表 單,而后進行查詢操作。在我們解析表單時,為了方便起見,常常喜歡將一些不需要查詢的條件用永真的條件來代替(如:select count(id) from x_table where name like ‘%’),其實這樣的SQL對資源的浪費是相當可怕的。我試過對于同樣的近一千萬條記錄的查詢來說,使用select count(id) from x_table 進行表查詢需要11秒,而使用select count(id) from x_table where name like ‘%’卻花了33秒。?
4、避免在查詢時使用表連接?
在做海量數(shù)據(jù)查詢時,應盡量避免表連接(特別是左、右連接),萬不得已要進行表連接時,被連接的另一張表數(shù)據(jù)量一定不能太大,若連接的另一張表也是數(shù)萬條的話,那估計可以考慮重新設計庫表了,因為那需要等待的時間決不是正常用戶所能忍受的。?
5、嵌套查詢時,盡可能地在第一次select就把查詢范圍縮到最小?
在有多個select嵌套查詢的時候,應盡量在最內(nèi)層就把所要查詢的范圍縮到最小,能分頁的先分頁。很多時候,就是這樣簡單地把分頁放到內(nèi)層查詢里,對查詢效率來說能形成質(zhì)的變化。?
特別是銀行系統(tǒng)的,數(shù)量級是億級別的,所以更要考慮下面的方法。
1,怎樣造Java對象。有句話說得好:盡可能的少造對象。別說千萬級,就是上萬級都不要考慮造對象了。因為幾個請求一并發(fā),喀嚓,系統(tǒng)肯定完蛋。
2,合理擺正系統(tǒng)設計的位置。大量數(shù)據(jù)操作,和少量數(shù)據(jù)操作一定是分開的。大量的數(shù)據(jù)操作,肯定不是ORM框架搞定的。絕對不能ORM,因為1,要少造對象;2,數(shù)據(jù)庫資源合理利用。就像博主的例子:id分配就是一個好例子。
3,合理利用數(shù)據(jù)庫的分區(qū)、索引技術。
4,有的時候可以考慮臨時表之類的,尤其是大數(shù)據(jù)量。
5,有人說非常大的數(shù)據(jù)量,一定要用存儲過程:jdbc,效果非常好
6,控制好內(nèi)存,讓數(shù)據(jù)流起來,而不是全部讀到內(nèi)存再處理,而是邊讀取邊處理;
7,合理利用內(nèi)存,有的數(shù)據(jù)要緩存。