android服务器 性能,Android性能优化(中)
Android性能優(yōu)化
在上一篇中介紹了性能優(yōu)化的概念、內(nèi)存泄漏和性能優(yōu)化方式
Android性能優(yōu)化(上)
我們繼續(xù)說說Android性能優(yōu)化
數(shù)據(jù)庫性能優(yōu)化
索引
簡單的說,索引就像書本的目錄,目錄可以快速找到所在頁數(shù),數(shù)據(jù)庫中索引可以幫助快速找到數(shù)據(jù),而不用全表掃描,合適的索引可以大大提高數(shù)據(jù)庫查詢的效率。
(1). 優(yōu)點
大大加快了數(shù)據(jù)庫檢索的速度,包括對單表查詢、連表查詢、分組查詢、排序查詢。經(jīng)常是一到兩個數(shù)量級的性能提升,且隨著數(shù)據(jù)數(shù)量級增長。
(2). 缺點
索引的創(chuàng)建和維護存在消耗,索引會占用物理空間,且隨著數(shù)據(jù)量的增加而增加。在對數(shù)據(jù)庫進行增刪改時需要維護索引,所以會對增刪改的性能存在影響。
使用場景
A.當(dāng)某字段數(shù)據(jù)更新頻率較低,查詢頻率較高,經(jīng)常有范圍查詢(>, =, <=)或order by、group by發(fā)生時建議使用索引。并且選擇度越大,建索引越有優(yōu)勢,這里選擇度指一個字段中唯一值的數(shù)量/總的數(shù)量。
B. 經(jīng)常同時存取多列,且每列都含有重復(fù)值可考慮建立復(fù)合索引
索引分類
直接創(chuàng)建索引和間接創(chuàng)建索引
直接創(chuàng)建: 使用sql語句創(chuàng)建,Android中可以在SQLiteOpenHelper的onCreate或是onUpgrade中直接excuSql創(chuàng)建語句,語句如
CREATE INDEX mycolumn_index ON mytable (myclumn)
間接創(chuàng)建: 定義主鍵約束或者唯一性鍵約束,可以間接創(chuàng)建索引,主鍵默認為唯一索引。
普通索引和唯一性索引
普通索引:CREATE INDEX mycolumn_index ON mytable (myclumn)
唯一性索引:保證在索引列中的全部數(shù)據(jù)是唯一的,對聚簇索引和非聚簇索引都可以使用,語句為CREATE UNIQUE COUSTERED INDEX myclumn_cindex ON mytable(mycolumn)
單個索引和復(fù)合索引
單個索引:索引建立語句中僅包含單個字段,如上面的普通索引和唯一性索引創(chuàng)建示例。
復(fù)合索引:又叫組合索引,在索引建立語句中同時包含多個字段,語句如:CREATE INDEX name_index ON username(firstname, lastname),其中firstname為前導(dǎo)列。
聚簇索引和非聚簇索引(聚集索引,群集索引)
聚簇索引:物理索引,與基表的物理順序相同,數(shù)據(jù)值的順序總是按照順序排列,語句為:CREATE CLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn) WITH ALLOW_DUP_ROW,其中WITH ALLOW_DUP_ROW表示允許有重復(fù)記錄的聚簇索引
非聚簇索引:CREATE UNCLUSTERED INDEX mycolumn_cindex ON mytable(mycolumn)
索引默認為非聚簇索引
使用規(guī)則
對于復(fù)合索引,把使用最頻繁的列做為前導(dǎo)列(索引中第一個字段)。如果查詢時前導(dǎo)列不在查詢條件中則該復(fù)合索引不會被使用。
如create unique index PK_GRADE_CLASS on student (grade, class)
select * from student where class = 2未使用到索引
select * from dept where grade = 3使用到了索引
避免對索引列進行計算,對where子句列的任何計算如果不能被編譯優(yōu)化,都會導(dǎo)致查詢時索引失效
select * from student where tochar(grade)=’2′
比較值避免使用NULL
多表查詢時要注意是選擇合適的表做為內(nèi)表。連接條件要充份考慮帶有索引的表、行數(shù)多的表,內(nèi)外表的選擇可由公式:外層表中的匹配行數(shù)
內(nèi)層表中每一次查找的次數(shù)確定,乘積最小為最佳方案。實際多表操作在被實際執(zhí)行前,查詢優(yōu)化器會根據(jù)連接條件,列出幾組可能的連接方案并從中找出系統(tǒng)開銷最小的最佳方案。
查詢列與索引列次序一致
用多表連接代替EXISTS子句
把過濾記錄數(shù)最多的條件放在最前面
善于使用存儲過程,它使sql變得更加靈活和高效(Sqlite不支持存儲過程::>_<::>
事務(wù)
使用事務(wù)的兩大好處是原子提交和更優(yōu)性能。
原子提交
原子提交意味著同一事務(wù)內(nèi)的所有修改要么都完成要么都不做,如果某個修改失敗,會自動回滾使得所有修改不生效。
更優(yōu)性能
Sqlite默認會為每個插入、更新操作創(chuàng)建一個事務(wù),并且在每次插入、更新后立即提交。
這樣如果連續(xù)插入100次數(shù)據(jù)實際是創(chuàng)建事務(wù)->執(zhí)行語句->提交這個過程被重復(fù)執(zhí)行了100次。如果我們顯式的創(chuàng)建事務(wù)->執(zhí)行100條語句->提交會使得這個創(chuàng)建事務(wù)和提交這個過程只做一次,通過這種一次性事務(wù)可以使得性能大幅提升。尤其當(dāng)數(shù)據(jù)庫位于sd卡時,時間上能節(jié)省兩個數(shù)量級左右。
Sqlte顯示使用事務(wù),示例代碼如下:
public void insertWithOneTransaction() {
SQLiteDatabase db = sqliteOpenHelper.getWritableDatabase();
//開始一個事務(wù)
db.beginTransaction();
try {
for (int i = 0; i < 100; i++) {
db.insert(yourTableName, null, value);
}
// 設(shè)置當(dāng)前事務(wù)成功
db.setTransactionSuccessful();
} catch (Exception e) {
e.printStackTrace();
} finally {
//結(jié)束事務(wù)
db.endTransaction();
}
}
其中sqliteOpenHelper.getWritableDatabase()表示得到寫表權(quán)限。
其他Sqlite的優(yōu)化
語句的拼接使用StringBuilder代替String
簡單的String相加會導(dǎo)致創(chuàng)建多個臨時對象消耗性能。StringBuilder的空間預(yù)分配性能好得多。如果你對字符串的長度有大致了解,如100字符左右,可以直接new StringBuilder(128)指定初始大小,減少空間不夠時的再次分配。
查詢時返回更少的結(jié)果集及更少的字段。
查詢時只取需要的字段和結(jié)果集,更多的結(jié)果集會消耗更多的時間及內(nèi)存,更多的字段會導(dǎo)致更多的內(nèi)存消耗。
少用cursor.getColumnIndex
根據(jù)性能調(diào)優(yōu)過程中的觀察cursor.getColumnIndex的時間消耗跟cursor.getInt(索引號)相差無幾。可以在建表的時候用static變量記住某列的index,直接調(diào)用相應(yīng)index而不是每次查詢。
public static final String HTTP_RESPONSE_TABLE_ID = _ID;
public static final String HTTP_RESPONSE_TABLE_RESPONSE = "response";
public List getData() {
……
cursor.getString(cursor.getColumnIndex(HTTP_RESPONSE_TABLE_RESPONSE));
……
}
//優(yōu)化為
public static final String HTTP_RESPONSE_TABLE_ID = _ID;
public static final String HTTP_RESPONSE_TABLE_RESPONSE = "response";
public static final int HTTP_RESPONSE_TABLE_ID_INDEX = 0;
public static final int HTTP_RESPONSE_TABLE_URL_INDEX = 1;
public List getData() {
……
cursor.getString(HTTP_RESPONSE_TABLE_RESPONSE_INDEX);
……
}
異步線程
Sqlite是常用于嵌入式開發(fā)中的關(guān)系型數(shù)據(jù)庫,完全開源。與Web常用的數(shù)據(jù)庫Mysql、Oracle db、sql server不同,Sqlite是一個內(nèi)嵌式的數(shù)據(jù)庫,數(shù)據(jù)庫服務(wù)器就在你的程序中,無需網(wǎng)絡(luò)配置和管理,數(shù)據(jù)庫服務(wù)器端和客戶端運行在同一進程內(nèi),減少了網(wǎng)絡(luò)訪問的消耗,簡化了數(shù)據(jù)庫管理。不過Sqlite在并發(fā)、數(shù)據(jù)庫大小、網(wǎng)絡(luò)方面存在局限性,并且為表級鎖,所以也沒必要多線程操作。
Android中數(shù)據(jù)不多時表查詢可能耗時不多,不會導(dǎo)致ANR,不過大于100ms時同樣會讓用戶感覺到延時和卡頓,可以放在線程中運行,但Sqlite在并發(fā)方面存在局限,多線程控制較麻煩,這時候可使用單線程池,在任務(wù)中執(zhí)行db操作,通過Handler返回結(jié)果和UI線程交互,既不會影響UI線程,同時也能防止并發(fā)帶來的異常。
可使用Android提供的AsyncQueryHandler或類似如下代碼完成:
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
db.insert("你的表名", null, value);
handler.sendEmptyMessage(xx);
}
});
移動網(wǎng)絡(luò)優(yōu)化
一個網(wǎng)絡(luò)請求可以簡單分為連接服務(wù)器 -> 獲取數(shù)據(jù)兩個部分。
其中連接服務(wù)器前還包括DNS解析的過程;獲取數(shù)據(jù)后可能會對數(shù)據(jù)進行緩存。
連接服務(wù)器優(yōu)化策略
不用域名,用IP直連
省去 DNS 解析過程,DNS 全名 Domain Name System,解析意指根據(jù)域名得到其對應(yīng)的 IP 地址。
如:http://www.codekk.com 的域名解析結(jié)果就是104.236.147.76。
首次域名解析一般需要幾百毫秒,可通過直接向IP而非域名請求,節(jié)省掉這部分時間,同時可以預(yù)防域名劫持等帶來的風(fēng)險。
當(dāng)然為了安全和擴展考慮,這個IP可能是一個動態(tài)更新的IP列表,并在IP不可用情況下通過域名訪問。
服務(wù)器合理部署
配合上面說到的動態(tài) IP 列表,支持優(yōu)先級,每次根據(jù)地域、網(wǎng)絡(luò)類型等選擇最優(yōu)的服務(wù)器IP進行連接。
對于服務(wù)器端還可以調(diào)優(yōu)服務(wù)器的TCP擁塞窗口大小、重傳超時時間(RTO)、最大傳輸單元(MTU)等。
獲取數(shù)據(jù)優(yōu)化策略
連接復(fù)用
節(jié)省連接建立時間,如開啟keep-alive
Http 1.1 默認啟動了keep-alive。對于Android來說默認情況下HttpURLConnection 和HttpClient都開啟了keep-alive。
其他網(wǎng)絡(luò)請求框架也可以進行相應(yīng)配置
請求合并
即將多個請求合并為一個進行請求,比較常見的就是網(wǎng)頁中的CSS Image Sprites。 如果某個頁面內(nèi)請求過多,也可以考慮做一定的請求合并。
減小請求數(shù)據(jù)大小
對于 POST 請求,Body 可以做 Gzip 壓縮,如日志。
對請求頭進行壓縮
這個http 1.1不支持,spdy及http 2.0支持。http 1.1 可以通過服務(wù)端對前一個請求的請求頭進行緩存,后面相同請求頭用md5之類的id來表示即可。
CDN緩存靜態(tài)資源
緩存常見的圖片、JS、CSS 等靜態(tài)資源。
減小返回數(shù)據(jù)大小
壓縮
一般API數(shù)據(jù)使用Gzip壓縮
精簡數(shù)據(jù)格式
如JSON代替 XML,WebP代替其他圖片格式
對于不同的設(shè)備不同網(wǎng)絡(luò)返回不同的內(nèi)容 如不同分辨率圖片大小。
增量更新
需要數(shù)據(jù)更新時,可考慮增量更新。如常見的服務(wù)端進行bsdiff,客戶端進行 bspatch。
大文件下載
支持斷點續(xù)傳,并緩存Http Resonse的ETag標識,下次請求時帶上,從而確定是否數(shù)據(jù)改變過,未改變則直接返回304。
數(shù)據(jù)緩存
緩存獲取到的數(shù)據(jù),在一定的有效時間內(nèi)再次請求可以直接從緩存讀取數(shù)據(jù)。
現(xiàn)在的網(wǎng)絡(luò)請求框架都可進行相應(yīng)的緩存配置
今天周末,就說這么多(懶),祝大家周末Happy
總結(jié)
以上是默认站点為你收集整理的android服务器 性能,Android性能优化(中)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言循环链表中设立尾链表,C语言实现双
- 下一篇: 如何将多个Android Wear手表与