天天看點

軟體性能優化最佳實踐

軟體性能優化最佳實踐

(作者:a_yu)

1 經驗總結

1.1 應用程式設計優化

大業務量資料存儲設計建議

當系統中業務資料量較大時,避免業務變更的曆史資料和正式的業務資料同時存儲,由于業務新增的資料及曆史業務變更産生的資料,會到時存儲表越來越龐大,而且曆史資料會逐漸增多,一段時間後,曆史資料往往會大于正式資料,而正式資料是要經常使用的,曆史資料隻會在個别查詢時會用到,龐大的資料存儲會直接導緻正式業務資料的查詢性能及程式處理複雜度,同時,如果系統未來進行更新時,龐大的資料量會大大增大資料遷移割接的難度,增加資料遷移的時間;建議将正式資料獨立存儲,業務修改後的曆史資料采用日志存儲或建立表進行存儲,保證正式資料的查詢處理效率。

對于不可變字元類型char和可變字元類型varchar 最大長度都是8000位元組,char查詢快,但是耗存儲空間,varchar查詢相對慢一些但是節省存儲空間。在設計字段的時候可以靈活選擇,例如使用者名、密碼等長度變化不大的字段可以選擇CHAR,對于評論等長度變化大的字段可以選擇VARCHAR。

資料行的長度不要超過8020位元組,如果超過這個長度的話在實體頁中這條資料會占用兩行進而造成存儲碎片,降低查詢效率。

能夠用數字類型的字段盡量選擇數字類型而不用字元串類型的(電話号碼),這會降低查詢和連接配接的性能,并會增加存儲開銷。這是因為引擎在處理查詢和連接配接回逐個比較字元串中每一個字元,而對于數字型而言隻需要比較一次就夠了。

字段的長度在最大限度的滿足可能的需要的前提下,應該盡可能的設得短一些,這樣可以提高查詢的效率,而且在建立索引的時候也可以減少資源的消耗。

曆史資料存儲建議

當資料庫中的某種業務資料增加量很大時,如短信業務或使用者交易業務,往往涉及最近記錄和曆史記錄查詢問題,建議建立與正式業務表屬性相同的曆史記錄表,同時采用定時程式或存儲過程等方法将正式業務表的資料按過期規則遷移至曆史記錄表,在使用者進行記錄查詢是分表查詢,一般使用者比較關注近期的記錄,這樣直接查詢正式業務表,資料量不是很大,保證的較高的查詢響應效率,個别情況下使用者會查詢曆史記錄,系統會從曆史記錄表中查詢;使用這樣的方式可以保證大部分時間使用者的查詢效率

消息服務的應用

J2EE規範在JMS中提供了内置的異步處理服務。當涉及到系統需求時,應該了解在什麼情況下應該采用JMS進行異步處理的設計。一旦确定要執行一些異步處理,那麼同步處理的任務就應該越少越好,将資料庫密集的操作安排在稍後的異步進行中完成。

大字段處理

當業務表中包括用來存儲附件、圖檔、大文本的大字段的資料類型時,在清單頁面一般情況下不要擷取大字段内容,如清單頁面擷取大字段,卻不進行展現,如資料量增大後,會大大影響頁面展示速度,在檢視頁面加載大字段類型,可在對象實體類中增加一個鈎子函數,隻把基本屬性傳入,這樣清單頁面就不會擷取到大字段,當然,也可以通過Hibernate配置解決這個問題,hibernate2可以将BLOB字段與基本資訊分離,生成兩個PO,這樣我們可以通過延遲加載特性以提高效率,字段單獨拆分出來,以提高資料庫操作的性能。Hibernate3中對于POJO的屬性提供了延遲加載, 隻要設定屬性的的lazy="true",以後通過getXXX才能真正從資料庫中讀取資料,這樣可以有效地提高我們讀取部分表字段的性能。

流的關閉

對于應用中的I/O流、網絡傳輸流、資料庫連接配接等要及時關閉和釋放,否則會造成記憶體溢出,會話數占滿等問題。在流關閉的時候要注意關閉的順序。

1.2 資料庫優化

連接配接池配置

目前資料庫連接配接池開源元件是非常多的,DBCP、C3P0、Proxool、BoneCP等都是非常優秀的産品。連接配接池的性能和穩定性會對我們的程式造成極大的影響,是以,有必要對這些連接配接池産品進行一些選擇。另外,連接配接池的配置是否恰當,将會決定該連接配接池的性能和穩定性表現,Hibernate開發組推薦使用c3p0,spring開發組推薦使用dbcp(dbcp連接配接池有weblogic連接配接池同樣的問題,就是強行關閉連接配接或資料庫重新開機後,無法reconnect,但可通過配置來解決),Hibernate in action推薦使用c3p0和proxool。三個産品都能很友善地整合到Springframework中,也都可以配置為JNDI資源,是以,它們可以随意更換,不會影響程式代碼。根據網絡上各種比較結果分析,在性能上,BoneCP>Proxool>C3P0>DBCP,在穩定性上DBCP>C3P0>Proxool。是以在項目中要根據實際情況,選擇适當的連接配接池。針對大批量的資料處理建議使用JDBC。

緩存配置

Hibernate提供了兩級緩存,第一級是Session的緩存。由于Session對象的生命周期通常對應一個資料庫事務或者一個應用事務,是以它的緩存是事務範圍的緩存。第一級緩存是必需的,不但而且事實上也無法被卸除。在第一級緩存中,持久化類的每個執行個體都具有唯一的OID。第二級緩存是一個可插拔的的緩存插件,它是由SessionFactory負責管理。由于SessionFactory對象的生命周期和應用程式的整個過程對應,是以第二級緩存是程序範圍或者叢集範圍的緩存。這個緩存中存放的對象的松散資料。第二級對象有可能出現并發問題,是以需要采用适當的并發通路政策,該政策為被緩存的資料提供了事務隔離級别。緩存擴充卡用于把具體的緩存實作軟體與Hibernate內建。第二級緩存是可選的,可以在每個類或每個集合的粒度上配置第二級緩存。

正确的利用二級緩存,可極大的提高系統的查詢效率。

以下資料适合存放到第二級緩存中:

 很少被修改的資料

 不是很重要的資料,但出現偶然并發的資料

 不會被并發通路的資料

 參考資料

以下資料不适合存放到第二級緩存中:

 經常被修改的資料

 财務資料,絕對不能出現并發

 與其他應用共享的資料。

SQL優化

我們要做到不但會寫 SQL,還要做到寫出性能優良的 SQL。SQL優化需要注意及遵循的準則很多,本文隻列舉核心部分:

1) 盡量少用IN操作符,基本上所有的IN操作符都可以用EXISTS代替。

2) 不用NOT IN操作符,可以用NOT EXISTS或者外連接配接+(外連接配接+判斷為空)替代。

3) 不用“<>”或者“!=”操作符。對不等于操作符的處理會造成全表掃描,可以用“<” or “>”代替。例如:a<>0 改為 a>0 or a<0,a<>’ ’ 改為 a>’ ’

4) Where子句中出現IS NULL或者IS NOT NULL時,Oracle會停止使用索引而執行全表掃描。可以考慮在設計表時,對索引列設定為NOT NULL。這樣就可以用其他操作來取代判斷NULL的操作。

5) 當通配符“%”或者“_”作為查詢字元串的第一個字元時,索引不會被使用,是以一般不要作為第一個字元出現。

6) 對于有連接配接的列“||”,最後一個連接配接列索引會無效。盡量避免連接配接,可以分開連接配接或者使用不作用在列上的函數替代。

7) 如果索引不是基于函數的,那麼當在Where子句中對索引列使用函數時,索引不再起作用。

8) Where子句中避免在索引列上使用計算,否則将導緻索引失效而進行全表掃描。

9) 對資料類型不同的列進行比較時,會使索引失效。

10) 用“>=”替代“>”。

11) UNION操作符會對結果進行篩選,消除重複,資料量大的情況下可能會引起磁盤排序。如果不需要删除重複記錄,應該使用UNION ALL。

12) Oracle從下到上處理Where子句中多個查詢條件,是以表連接配接語句應寫在其他Where條件前,可以過濾掉最大數量記錄的條件必須寫在Where子句的末尾。

13) Oracle從右到左處理From子句中的表名,是以在From子句中包含多個表的情況下,将記錄最少的表放在最後。

14) Order By語句中的非索引列會降低性能,可以通過添加索引的方式處理。嚴格控制在Order By語句中使用表達式。

15) 不同區域出現的相同的Sql語句,要保證查詢字元完全相同,以利用SGA共享池,防止相同的Sql語句被多次分析。

16) 多利用内部函數提高Sql效率。

17) 當在Sql語句中連接配接多個表時,使用表的别名,并将之作為每列的字首。這樣可以減少解析時間。

18) 根據SQL不同設定優化模式的方式,選擇不同的優化政策,通過SELECT ……;來設定。可用的HINT包括、、、 等一般在SQL前加first_rows政策,速度都會提高,特殊情況下改用choose政策。

19) 對于大表查詢中的列應盡量避免進行諸如To_char,to_date,to_number等轉換。

20) 有索引的盡量用索引,有用到索引的條件寫在前面 。

21) 如有可能和有必要就建立一些索引 ,在使用索引字段作為條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個字段作為條件時才能保證系統使用該索引,否則該索引将不會被使用,并且應盡可能的讓字段順序與索引順序相一緻。

22) 盡量避免進行全表掃描,限制條件盡可能多,以便更快搜尋到要查詢的資料。

23) Select子句中盡量避免使用‘*’,當你想在SELECT子句中列出所有的COLUMN時,使用動态SQL列引用 ‘*’ 是一個友善的方法。但是,這是一個非常低效的方法。實際上,ORACLE在解析的過程中,會将‘*’ 依次轉換成所有的列名,這個工作是通過查詢資料字典完成的,這意味着将耗費更多的時間。合理寫WHERE子句,不要寫沒有WHERE的SQL語句。

24) 減少通路資料的次數,當執行每條SQL語句時, 資料庫在内部執行了許多工作: 解析SQL語句, 估算索引的使用率, 綁定變量 , 讀資料塊等等。 由此可見, 減少通路資料庫的次數 , 就能實際上減少資料庫的工作量。

25) 查詢的模糊比對,盡量避免在一個複雜查詢裡面使用 LIKE '%parm1%'——百分号會導緻相關列的索引無法使用,最好不要用。解決辦法:其實隻需要對該腳本略做改進,查詢速度便會提高近百倍。改進方法如下:

a、修改前台程式——把查詢條件的供應商名稱一欄由原來的文本輸入改為下拉清單,使用者模糊輸入供應商名稱時,直接在前台就幫忙定位到具體的供應商,這樣在調用背景程式時,這列就可以直接用等于來關聯了。

b、直接修改背景——根據輸入條件,先查出符合條件的供應商,并把相關記錄儲存在一個臨時表裡頭,然後再用臨時表去做複雜關聯。

盡量避免在索引過的字元資料中,使用非打頭字母搜尋。這也使得引擎無法利用索引。 見如下例子:

SELECT * FROM T1 WHERE NAME LIKE ‘%L%’

SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)=’L’

SELECT * FROM T1 WHERE NAME LIKE ‘L%’

即使NAME字段建有索引,前兩個查詢依然無法利用索引完成加快操作,引擎不得不對全表所有資料逐條操作來完成任務。而第三個查詢能夠使用索引來加快操作。

26) 避免使用耗費資源的操作,帶有DISTINCT,UNION,MINUS,INTERSECT,ORDER BY的SQL語句會啟動SQL引擎 執行,耗費資源的排序(SORT)功能. DISTINCT需要一次排序操作, 而其他的至少需要執行兩次排序。

27) 盡量減少重複工作,控制同一條語句的多次執行,減少多次的資料轉換,減少不必要的子查詢和連接配接表,合并對同一張表的多次update操作,update操作不要拆成delete+insert操作,雖然功能相同,但性能差别很大。

28) 多表連接配接的連接配接條件對索引選擇有重要意義,在寫連接配接條件時要特别注意。多表連接配接時,連接配接條件必須寫全,盡量使用聚集索引。

充分利用連接配接條件,在某種情況下,兩個表之間可能不隻一個的連接配接條件,這時在 WHERE 子句中将連接配接條件完整的寫上,有可能大大提高查詢速度。

例:

SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO

SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO AND A.ACCOUNT_NO=B.ACCOUNT_NO

第二句将比第一句執行快得多。

29) 避免使用不相容的資料類型。例如float和int、char和varchar、binary和varbinary是不相容的。資料類型的不相容可能使優化器無法執行一些本來可以進行的優化操作。例如:

SELECT name FROM employee WHERE salary > 60000

在這條語句中,如salary字段是money型的,則優化器很難對其進行優化,因為60000是個整型數。我們應當在程式設計時将整型轉化成為錢币型,而不要等到運作時轉化。

30) 盡量不要用SELECT INTO語句。

SELECT INTO 語句會導緻表鎖定,阻止其他使用者通路該表。

31) 使用視圖加速查詢。

把表的一個子集進行排序并建立視圖,有時能加速查詢。它有助于避免多重排序操作,而且在其他方面還能簡化優化器的工作。視圖中的行要比主表中的行少,而且實體順序就是所要求的順序,減少了磁盤I/O,是以查詢工作量可以得到大幅減少。

建立高效的索引

索引是從資料庫中擷取資料的最高效方式之一。95% 的資料庫性能問題都可以采用索引技術得到解決。

不必要的全表搜尋導緻大量不必要的I/O,進而拖慢整個資料庫的性能。調優專家首先會根據查詢傳回的行數目來評價 SQL。在一個有序的表中,如果查詢傳回少于40%的行,或者在一個無序的表中,傳回少于7%的行,那麼這個查詢都可以調整為使用一個索引來代替全表搜尋。對于不必要的全表搜尋來說,最常見的調優方法是增加索引。可以在表中加入标準的B樹索引,也可以加入bitmap和基于函數的索引。要決定是否消除一個全表搜尋,你可以仔細檢查索引搜尋的I/O開銷和全表搜尋的開銷,它們的開銷和資料塊的讀取和可能的并行執行有關,并将兩者作對比。在一些情況下,一些不必要的全表搜尋的消除可以通過強制使用一個index來達到,隻需要在SQL語句中加入一個索引的提示就可以了。J2EE的架構設計工程師和開發人員通常不是SQL專家或經驗豐富的資料庫管理者。首先應該確定SQL使用了資料庫提供的索引支援。在關鍵查詢屬性上增加索引,會極大的提高資料庫表查詢速率,在某些情況下,将資料庫的索引和資料分開存放會提高性能。但要知道,增加額外的索引可以提高SELECT性能但也會降低INSERT的性能。

在做性能跟蹤分析過程中,經常發現有不少背景程式的性能問題是因為缺少合适索引造成的,有些表甚至一個索引都沒有。這種情況往往都是因為在設計表時,沒去定義索引,而開發初期,由于表記錄很少,索引建立與否,可能對性能沒啥影響,開發人員是以也未多加重視。然一旦程式釋出到生産環境,随着時間的推移,表記錄越來越多這時缺少索引,對性能的影響便會越來越大了。這個問題需要資料庫設計人員和開發人員共同關注。

法則:不要在建立的索引的資料列上進行下列操作:

◆避免對索引字段進行計算操作

◆避免在索引字段上使用not,<>,!=

◆避免在索引列上使用IS NULL和IS NOT NULL

◆避免在索引列上出現資料類型轉換

◆避免在索引字段上使用函數

◆避免建立索引的列中使用空值。

作為一條規則,通常對邏輯主鍵使用唯一的聚集索引,對系統鍵(作為存儲過程)采用唯一的非聚集索引,對任何外鍵列[字段]采用非聚集索引。

存儲過程使用

對于比較複雜的業務,建議使用存儲過程,可以提高運作效率,減少網絡流量。但是存儲過程也要慎用,對于非常消耗資料庫性能的情況盡量使用存儲過程,如果要考慮開發的業務邏輯,且後期的業務變化比較頻繁的,不要使用存儲過程,會增加維護成本,是以存儲過程推薦使用,但也要有個度。

I/O讀寫分離

由于對于同一段資料,如果要同時寫入和讀出,會存在鎖的問題,影響效率,建議把I/O讀寫頻繁的資料進行分離,可以采用分庫、分表等方式進行分離。

分表空間、分表、分區

對于資料量比較大,業務類型清楚的表空間和表,可以進行分表空間、分表和分區的方式,有減小資料規模等的好處,能極大的提高資料庫的使用效率。對資料量很大的Table和Index使用分區,放在不同的Tablespace中。

備援設計

備援設計包括字段備援、表備援、視圖以及建立臨時表。對于有大量關聯查詢的情況,建議采用備援的方式,或者增加備援字段,或者增加中間表,或者增加視圖,或者建立臨時表,以犧牲空間的方式來換取時間效率。

提前計算

對于報表統計等大資料量的統計操作,如果速度太慢,可以提前進行計算,比如在晚上将統計結果查詢統計好後放在臨時區域,在第二天用的時候直接取臨時資料,會大大節省效率。

事務控制

事務方面對性能有影響的主要包括:事務方式的選用,事務隔離級别以及鎖的選用。

a)事務方式選用:如果不涉及多個事務管理器事務的話,不需要使用JTA,隻有JDBC的事務控制就可以。

b)事務隔離級别:參見标準的SQL事務隔離級别

c)鎖的選用:悲觀鎖(一般由具體的事務管理器實作),對于長事務效率低,但安全。樂觀鎖(一般在應用級别實作),如在HIBERNATE中可以定義 VERSION字段,顯然,如果有多個應用操作資料,且這些應用不是用同一種樂觀鎖機制,則樂觀鎖會失效。

叢集

如果系統的瓶頸主要在資料庫的并發操作比較高,可以考慮采用資料庫叢集的方式來提高資料庫操作的性能。資料庫叢集是利用一個叢集中的多台機器共同完成同一件任務,使得完成任務的速度和可靠性都遠高于單機運作的效果。資料庫叢集在資料量大,計算複雜的環境用的比較多。

1.3 部署環境優化

應用伺服器配置優化

針對你系統特點定制應用伺服器配置。應用伺服器設定對性能和吞吐量有重要的影響,包括:

 資料庫連接配接池大小。這對吞吐量有至關重要的影響。連接配接池太小會導緻線程因等待連接配接釋放而阻塞;而太大的連接配接池在叢集環境中可能帶來問題,資料庫可能耗光連接配接監聽器。

 線程池大小。線程池太小會浪費CPU能力,太大的線程池可能反而降低性能。

 使用SLSB(無狀态會話bean)時的執行個體池大小。它的影響和線程池相似。不要把它設定得比線程池更大。

 使用SLSB時的事務描述符。除非業務對象的所有方法都是需要是事務的,不要對所有方法都使用同樣的事務聲明。确定每個方法都有合适的事務屬性:如果不需要事務就是none。

 HTTP session複制選項。根據你的應用程式選擇是把session儲存到資料庫還是保持在記憶體中,仔細檢查你的應用伺服器提供的選項。

 JTA選項。假若隻使用一個資料庫,必須確定你沒有使用開銷巨大的XA事務。

 log設定。應用伺服器和應用程式一樣都會産生log輸出,這可能造成巨大的開銷,記住讓你的伺服器隻産生必要的資訊log。

伺服器硬體環境優化

確定伺服器網絡達到設計要求。如果在硬體資源充沛的情況下,我們首先應該對硬體環境進行優化,比如更換更加高性能的伺服器裝置,增大記憶體,提高網絡帶寬,采用磁陣存儲等。

叢集、負載均衡

在系統運作時,web伺服器往往要支撐大量密集的使用者點選和對動态内容的需求,是以即使再高檔的伺服器裝置,面對不斷增加的使用者,機關時間内所支援的通路量也會有一個限度,尤其是對于動态内容較多的情況:因為動态内容的應用需要頻繁地調用資料庫的資料和應用程式,會占用大量的伺服器資源。這時就需要在多個伺服器裝置之間或多個站點之間分散伺服器的負載。可以對Jboss、Tomcat等常用的應用伺服器結合Apache進行負載均衡,以減輕單個web伺服器的壓力,提升高并發量情況下的系統性能。

1.4 其他優化

系統日志優化

将日志檔案的大小設定為合理大小,以防止日志檔案過大影響到性能。隻記錄必要的日志(如Error級别以上的日志),盡量減少日志的輸出量。在代碼中,删除不必要的列印語句。

靜态類合理使用

Java類中的靜态變量在程式運作期間,其記憶體空間對所有該類的對象執行個體而言是共享的,有些時候可以認為是全局變量。是以在某些時候為了節省系統記憶體開銷、共享資源,可以将類中的一些變量聲明為靜态變量,因為靜态變量生命周期較長,而且不易被系統回收,是以如果不能合理地使用靜态變量,就會适得其反,造成大量的記憶體浪費,在高并發的時候造成stack記憶體溢出,所謂過猶不及。是以,建議在具備下列全部條件的情況下,盡量使用靜态變量:

(1)變量所包含的對象體積較大,占用記憶體較多。

(2)變量所包含的對象生命周期較長。

(3)變量所包含的對象資料穩定。

(4)該類的對象執行個體有對該變量所包含的對象的共享需求。

頁面優化

(1) 頁面減肥:頁面的肥瘦是影響加載速度最重要的因素 ,删除不必要的空格、注釋 ,将内聯引用的script和css移到外部檔案 ,可以使用HTML TIDY來給HTML減肥,還可以使用一些壓縮工具來給JavaScript減肥。

(2) 減少檔案數量:減少頁面上引用的檔案數量可以減少HTTP連接配接數 ,許多JavaScript、CSS檔案可以合并最好合并。

(3) 減少域名查詢:DNS查詢和解析域名也是消耗時間的,是以要減少對外部JavaScript、CSS、圖檔等資源的引用,不同域名的使用越少越好。

(4) 緩存重用資料:在頁面上緩存重用的資料,可以減少資料庫的IO操作次數,提高頁面展示速度。

(5) 優化頁面元素加載順序:首先加載頁面最初顯示的内容和與之相關的JavaScript和CSS ,然後加載DHTML相關的東西 ,像什麼不是最初顯示相關的圖檔、flash、視訊等很肥的資源就最後加載。建議把樣式表放在頂部、腳本放在底部。

(6) 減少HTML内聯引用javascript的數量:浏覽器parser會假設内聯引用JavaScript會改變頁面結構,是以使用内聯引用 JavaScript開銷較大 ,不要使用document.write()這種輸出内容的方法,使用标準W3C DOM方法來為現代浏覽器處理頁面内容。

(7) 使用标準的CSS和合法的标簽:使用标準CSS來減少标簽和圖像,例如使用标準CSS+文字完全可以替代一些隻有文字的圖檔 ,使用合法的标簽避免浏覽器解析HTML時做“error correction”等操作。

1.5 優化步驟

軟體的性能優化應該在需求采集階段就要了解清楚使用者對軟體的性能要求,比如最大的并發使用者數、資料的規模、網絡環境等,以便于在後續的設計和開發中對性能進行持續的優化。當在運作系統發生了性能問題後,我們往往措手不及,無從下手,其實,如果按照環境、應用、資料庫這3個層面分别去進行優化,總能找到相應的解決辦法。對于在運作系統,遇到性能問題後我們應該遵循“先環境後應用”、“先資料庫後程式”、“先易後難”的原則進行優化。

“先環境後應用”是指遇到性能問題了,我們不要急着去查應用的問題,先看看硬體環境或者部署環境有沒有出問題,比如看看網絡的帶寬是否正常,伺服器的I/O吞吐、記憶體使用率、CPU使用率是否正常。然後再看看作業系統、應用伺服器等是否正常,應用是否感染病毒等。這個原則适用于系統長期運作穩定,在系統使用環境沒有變化的情況下,突然出現性能問題。

“先資料庫後程式“是指遇到性能問題了,尤其是系統長期運作穩定,忽然由于使用者量的增長或者資料量的增長導緻出現性能問題的。先去查資料庫的工作狀況,比如會話數是否正常,有沒有長期占用不釋放的情況,索引是否有效,有沒有索引無效而全表掃描的情況,資料庫的I/O是否正常等。然後再根據資料庫的排查情況先去解決資料庫上的性能瓶頸,如本文提到的建立有效的索引、分表空間、分表(縱向和橫向)、分區等,如果這些的辦法還是行不通,再考慮去修改程式。

“先易後難”指的是在性能調優過程中,先嘗試使用簡單的,代價下的辦法去解決問題,如索引的排查、資料庫的排查、部署環境的排查,再去考慮複雜的辦法,如修改程式、修改資料結構、增加叢集等。

繼續閱讀