GreenDao與Realm性能對比

Realm compare with GreenDao

Android Studio配置

Realm環(huán)境配置

  • 在項目的 build.gradle 文件中添加如下 class path 依賴浑彰。
    • classpath "io.realm:realm-gradle-plugin:3.1.1"
  • 在 app 的 build.gradle 文件中應(yīng)用 realm-android 插件兜挨。
    • apply plugin: 'realm-android'

GreenDao環(huán)境配置

  • 在項目的 build.gradle 文件中進行以下配置

    • 在repositories添加 mavenCentral()
    • 在dependencies添加 classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
  • 在 app 的 build.gradle 文件中應(yīng)用 org.greenrobot.greendao 插件侍芝。

    • apply plugin: 'org.greenrobot.greendao'
  • 在 app 的 build.gradle 文件中添加兩個依懶

    • compile 'org.greenrobot:greendao:3.2.2'
    • compile 'org.greenrobot:greendao-generator:3.2.2'

自此Reaml和GreenDao配置完成,兩個的配置都是挺簡單躏尉。

數(shù)據(jù)庫類型的區(qū)別

Realm 是一個 MVCC 數(shù)據(jù)庫 , MVCC 在設(shè)計上采用了和 Git 一樣的源文件管理算法。你可以把 Realm 的內(nèi)部想象成一個 Git后众,它也有分支和原子化的提交操作胀糜。這意味著你可能工作在許多分支上(數(shù)據(jù)庫的版本),但是你卻沒有一個完整的數(shù)據(jù)拷貝蒂誉。Realm 和真正的 MVCC 數(shù)據(jù)庫還是有些不同的教藻。一個像 Git 的真正的 MVCC 數(shù)據(jù)庫,你可以有成為版本樹上 HEAD 的多個候選者右锨。而 Realm 在某個時刻只有一個寫操作括堤,而且總是操作最新的版本 - 它不可以在老的版本上工作。

GreenDao是一個ORM數(shù)據(jù)庫,對象-關(guān)系映射(OBJECT/RELATIONALMAPPING陡蝇,簡稱ORM)痊臭,用來把對象模型表示的對象映射到基于S Q L 的關(guān)系模型數(shù)據(jù)庫結(jié)構(gòu)中去。這樣登夫,我們在具體的操作實體對象的時候广匙,就不需要再去和復(fù)雜的 SQ L 語句打交道,只需簡單的操作實體對象的屬性和方法[2] 恼策。O R M 技術(shù)是在對象和關(guān)系之間提供了一條橋梁鸦致,前臺的對象型數(shù)據(jù)和數(shù)據(jù)庫中的關(guān)系型的數(shù)據(jù)通過這個橋梁來相互轉(zhuǎn)化[1]

Realm與GreenDao性能對比

對比前的準(zhǔn)備

  • 獲取CPU使用率和內(nèi)存變化工具類


public class SystemInfotil {

    /**
     * 獲取當(dāng)前cpu信息
     * @param context
     * @return
     */
    public static SystemInfo getProcessCpuRate(Context context) {
        float totalCpuTime1 = getTotalCpuTime();
        float processCpuTime1 = getAppCpuTime();

        return new SystemInfo(totalCpuTime1, processCpuTime1, displayBriefMemory(context));
    }

    /**
     * 獲取cpu使用率
     * @param startCpuInfo  開始時的信息
     * @param endCpuInfo    結(jié)束時的信息
     */
    public static float caculateRate(SystemInfo startCpuInfo, SystemInfo endCpuInfo) {
        return 100 * (endCpuInfo.processCpuTime - startCpuInfo.processCpuTime)
                / (endCpuInfo.totalCpuTime - startCpuInfo.totalCpuTime);
    }

    /**
     * 獲取cpu和內(nèi)存使用
     * @param startCpuInfo  開始時的信息
     * @param endCpuInfo    結(jié)束時的信息
     */
    public static String getRateString(SystemInfo startCpuInfo, SystemInfo endCpuInfo) {
        float cpuRate = caculateRate(startCpuInfo, endCpuInfo);
        return "; CPU:" + cpuRate + "; 內(nèi)存:" + (endCpuInfo.availibleMem - startCpuInfo.availibleMem);
    }

    /**
     * 其中,以CPU開頭的兩行表示的信息就是涣楷,當(dāng)前該CPI的一個總的使用情況分唾,后面各個數(shù)值的單位為jiffies,可以簡單理解為Linux中操作系統(tǒng)進程調(diào)度的最小時間片狮斗。具體含義如下(以CPU0為例):
     * user(181596)從系統(tǒng)啟動開始累計到當(dāng)前時刻绽乔,處于用戶態(tài)的運行時間,不包含 nice值為負進程碳褒。折砸;
     * nice(85733)從系統(tǒng)啟動開始累計到當(dāng)前時刻看疗,nice值為負的進程所占用的CPU時間;
     * system (197165)從系統(tǒng)啟動開始累計到當(dāng)前時刻睦授,處于核心態(tài)的運行時間两芳;
     * idle (1328127)從系統(tǒng)啟動開始累計到當(dāng)前時刻,除IO等待時間以外的其它等待時間去枷;
     * iowait(11679)從系統(tǒng)啟動開始累計到當(dāng)前時刻怖辆,IO等待時間;
     * softirq (5138)從系統(tǒng)啟動開始累計到當(dāng)前時刻删顶,軟中斷時間竖螃。
     * irq (5)從系統(tǒng)啟動開始累計到當(dāng)前時刻,硬中斷時間翼闹;
     * @return
     */
    public static long getTotalCpuTime() {
        String[] cpuInfos = null;
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream("/proc/stat")), 1000);
            String load = reader.readLine();
            reader.close();
            cpuInfos = load.split(" ");
        } catch (IOException ex) {
            ex.printStackTrace();
        }

        long totalCpu = Long.parseLong(cpuInfos[2])
                + Long.parseLong(cpuInfos[3]) + Long.parseLong(cpuInfos[4])
                + Long.parseLong(cpuInfos[6]) + Long.parseLong(cpuInfos[5])
                + Long.parseLong(cpuInfos[7]) + Long.parseLong(cpuInfos[8]);
        return totalCpu;
    }

    /**
     * 獲取應(yīng)用占用的CPU時間
     */
    public static long getAppCpuTime() {
        String[] cpuInfos = null;
        try {
            int pid = android.os.Process.myPid();
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream("/proc/" + pid + "/stat")), 1000);
            String load = reader.readLine();
            reader.close();
            cpuInfos = load.split(" ");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        long appCpuTime = Long.parseLong(cpuInfos[13])
                + Long.parseLong(cpuInfos[14]) + Long.parseLong(cpuInfos[15])
                + Long.parseLong(cpuInfos[16]);
        return appCpuTime;
    }

    /**
     * 獲取當(dāng)前內(nèi)存的使用量
     */
    public static float displayBriefMemory(Context context) {

        final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();

        activityManager.getMemoryInfo(info);

        return info.totalMem / 1024 / 1024;
    }


    public static class SystemInfo {

        float totalCpuTime;

        float processCpuTime;

        float availibleMem;

        SystemInfo(float totalCpuTime, float processCpuTime, float availibleMem) {
            this.totalCpuTime = totalCpuTime;
            this.processCpuTime = processCpuTime;
            this.availibleMem = availibleMem;
        }
    }
}



10次的插入平均資源消耗

GreenDao插入數(shù)據(jù)代碼實現(xiàn)和插入結(jié)果統(tǒng)計


long startIndex = System.currentTimeMillis();
for (int index = 0; index < insertCount; index ++) {
    user = new User(index + startIndex, GreenDaoActivity.NAME + ((int)(Math.random() * GreenDaoActivity.RANDOM_SIZE)) + "" + (startIndex + index));
    userDao.insertOrReplace(user);
}

插入數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 17.37% 0 30
20條 16.17% 0 57
100條 13.16% 0 270
1000條 11.46% 0 2663

Realm插入數(shù)據(jù)代碼實現(xiàn)和插入結(jié)果統(tǒng)計


for (int index = 0; index < insertCount; index ++) {
    final int finalIndex = index;
    Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            Contact contact = realm.createObject(Contact.class);
            contact.setName(GreenDaoActivity.NAME + ((int)(Math.random() * GreenDaoActivity.RANDOM_SIZE)) + "" + (startTime + finalIndex));
            contact.setSex(startTime + finalIndex);
        }
    });
}


插入數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 15.95% 0 38
20條 16.46% 0 65
100條 13.26% 0 277
1000條 13.53% 0 2735

從上圖得出的結(jié)論

  • Realm與GreenDao消耗CPU斑鼻,內(nèi)存和時間都差不多

10次的查詢的平均資源消耗

GreenDao查詢數(shù)據(jù)代碼實現(xiàn)和查詢結(jié)果統(tǒng)計


for (int index = 0; index < selectTime; index ++) {
    String startWidth = NAME +  + ((int)(Math.random() * RANDOM_SIZE));
    list = (ArrayList) getUserDao().queryBuilder().where(UserDao.Properties.Name.like("%" + startWidth + "%")).list();

    if (list != null && list.size() >= 0) {
        localList.addAll(list);
    }
}

查詢數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 31.67% 0 172
20條 30.34% 0 328
100條 27.35% 0 1619
1000條 25.71% 0 16121

Realm查詢數(shù)據(jù)代碼實現(xiàn)和查詢結(jié)果統(tǒng)計


for (int index = 0; index < selectTime; index ++) {
    Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            RealmResults realms = realm.where(Contact.class).beginsWith("name", GreenDaoActivity.NAME + ((int)(Math.random() * GreenDaoActivity.RANDOM_SIZE))).findAll();

            if (realms == null) {
                return;
            }
            counts[0] += realms.size();
        }
    });
}

查詢數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 21.35% 0 75
20條 20.46% 0 145
100條 20.35% 0 723
1000條 19.95% 0 7028

從上圖得出的結(jié)論

  • Realm在CPU和耗時上都要比GreenDao性能要好

10次的刪除平均資源消耗

GreenDao刪除數(shù)據(jù)代碼實現(xiàn)和刪除結(jié)果統(tǒng)計


for (int index = 0; index < deleteTimes; index ++) {
    getUserDao().delete(userIds.get(index));
    userIds.remove(index);
}

刪除數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 15.99% 0 41
20條 16.68% 0 76
100條 15.17% 0 371
1000條 15% 0 2771

Realm刪除數(shù)據(jù)代碼實現(xiàn)和刪除結(jié)果統(tǒng)計


for (int index = 0; index < deleteCount; index ++) {
    Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            RealmResults realmResults = realm.where(Contact.class).beginsWith("name", GreenDaoActivity.NAME + ((int)(Math.random() * GreenDaoActivity.RANDOM_SIZE))).findAll();

            if (realmResults.size() <= 0) {
                return;
            }
            counts[0] += realmResults.size();
            realmResults.deleteAllFromRealm();
        }
    });
}

刪除數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 23.13% 0 229
20條 21.56% 0 426
100條 20.45% 0 1729
1000條 17.04% 0 3359

從上圖得出的結(jié)論

  • GreenDao的刪除性能要比Realm要好

10次的更新平均資源消耗

GreenDao刪除數(shù)據(jù)代碼實現(xiàn)和刪除結(jié)果統(tǒng)計

for (int index = 0; index < deleteTimes; index ++) {
    User user = userIds.get(index);
    user.setName(user.getName() + "_____________NEW");
    getUserDao().update(user);
}

更新數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 13.81% 0 20
20條 14.96% 0 43
100條 14.04% 0 207
1000條 12.18% 0 1546

Realm刪除數(shù)據(jù)代碼實現(xiàn)和刪除結(jié)果統(tǒng)計



for (int index = 0; index < deleteTimes; index ++) {
    final int finalIndex = index;
    Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            Contact contact = realm.where(Contact.class).beginsWith("name", GreenDaoActivity.NAME + ((int)(Math.random() * GreenDaoActivity.RANDOM_SIZE))).findFirst();
            if (contact == null) {
                return;
            }
            counts[0] += 1;
            contact.setName(contact.getName() + "_____________NEW");
        }
    });
}


更新數(shù)量 CPU峰值 內(nèi)存消耗 CPU時間
10條 14.93% 0 30
20條 16.24% 0 57
100條 16.07% 0 277
1000條 14.94% 0 3121

從上圖得出的結(jié)論

  • GreenDao的更新性能比Realm略好一點

綜上所述

  • 插入1000條以內(nèi)的數(shù)據(jù)時,Realm與GreenDao不分伯仲
  • 查詢操作比較頻繁猎荠,就使用Realm
  • 刪除和更新操作比較頻繁坚弱,就使用GreenDao

需要說明的是使用Realm的話,打包成apk后关摇,大概會大4M左右荒叶,而GreenDao幾乎不會導(dǎo)致安裝包有太大的變化。但是Realm對于內(nèi)存優(yōu)化非常好输虱,號稱是Zero-copy

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末些楣,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宪睹,更是在濱河造成了極大的恐慌愁茁,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亭病,死亡現(xiàn)場離奇詭異鹅很,居然都是意外死亡,警方通過查閱死者的電腦和手機罪帖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門促煮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人整袁,你說我怎么就攤上這事菠齿。” “怎么了坐昙?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵绳匀,是天一觀的道長。 經(jīng)常有香客問我,道長襟士,這世上最難降的妖魔是什么盗飒? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮陋桂,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蝶溶。我一直安慰自己嗜历,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布抖所。 她就那樣靜靜地躺著梨州,像睡著了一般。 火紅的嫁衣襯著肌膚如雪田轧。 梳的紋絲不亂的頭發(fā)上暴匠,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音傻粘,去河邊找鬼每窖。 笑死,一個胖子當(dāng)著我的面吹牛弦悉,可吹牛的內(nèi)容都是我干的窒典。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼稽莉,長吁一口氣:“原來是場噩夢啊……” “哼瀑志!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起污秆,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤劈猪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后良拼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體战得,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年将饺,在試婚紗的時候發(fā)現(xiàn)自己被綠了贡避。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡予弧,死狀恐怖刮吧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掖蛤,我是刑警寧澤杀捻,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站蚓庭,受9級特大地震影響致讥,放射性物質(zhì)發(fā)生泄漏仅仆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一垢袱、第九天 我趴在偏房一處隱蔽的房頂上張望墓拜。 院中可真熱鬧,春花似錦请契、人聲如沸咳榜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涌韩。三九已至,卻和暖如春氯夷,著一層夾襖步出監(jiān)牢的瞬間臣樱,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工腮考, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留雇毫,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓秸仙,卻偏偏與公主長得像嘴拢,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子寂纪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容