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