Realm与GreenDao性能对比

阿凡达2018-08-01 13:39

Android Studio配置

Realm环境配置

  • 在项目的 build.gradle 文件中添加如下 class path 依赖。
    • classpath "io.realm:realm-gradle-plugin:3.1.1"
  • 在 app 的 build.gradle 文件中应用 realm-android 插件。
    • apply plugin: 'realm-android'

GreenDao环境配置

  • 在项目的 build.gradle 文件中进行以下配置

    • 在repositories添加 mavenCentral()
    • 在dependencies添加 classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
  • 在 app 的 build.gradle 文件中应用 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配置完成,两个的配置都是挺简单。

数据库类型的区别

Realm 是一个 MVCC 数据库 , MVCC 在设计上采用了和 Git 一样的源文件管理算法。你可以把 Realm 的内部想象成一个 Git,它也有分支和原子化的提交操作。这意味着你可能工作在许多分支上(数据库的版本),但是你却没有一个完整的数据拷贝。Realm 和真正的 MVCC 数据库还是有些不同的。一个像 Git 的真正的 MVCC 数据库,你可以有成为版本树上 HEAD 的多个候选者。而 Realm 在某个时刻只有一个写操作,而且总是操作最新的版本 - 它不可以在老的版本上工作。 详见.

GreenDao是一个ORM数据库,对象-关系映射(OBJECT/RELATIONALMAPPING,简称ORM),用来把对象模型表示的对象映射到基于S Q L 的关系模型数据库结构中去。这样,我们在具体的操作实体对象的时候,就不需要再去和复杂的 SQ L 语句打交道,只需简单的操作实体对象的属性和方法[2] 。O R M 技术是在对象和关系之间提供了一条桥梁,前台的对象型数据和数据库中的关系型的数据通过这个桥梁来相互转化[1]

Realm与GreenDao性能对比

对比前的准备

  • 获取CPU使用率和内存变化工具类



public class SystemInfotil {

    /**
     * 获取当前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    结束时的信息
     */
    public static float caculateRate(SystemInfo startCpuInfo, SystemInfo endCpuInfo) {
        return 100 * (endCpuInfo.processCpuTime - startCpuInfo.processCpuTime)
                / (endCpuInfo.totalCpuTime - startCpuInfo.totalCpuTime);
    }

    /**
     * 获取cpu和内存使用
     * @param startCpuInfo  开始时的信息
     * @param endCpuInfo    结束时的信息
     */
    public static String getRateString(SystemInfo startCpuInfo, SystemInfo endCpuInfo) {
        float cpuRate = caculateRate(startCpuInfo, endCpuInfo);
        return "; CPU:" + cpuRate + "; 内存:" + (endCpuInfo.availibleMem - startCpuInfo.availibleMem);
    }

    /**
     * 其中,以CPU开头的两行表示的信息就是,当前该CPI的一个总的使用情况,后面各个数值的单位为jiffies,可以简单理解为Linux中操作系统进程调度的最小时间片。具体含义如下(以CPU0为例):
     * user(181596)从系统启动开始累计到当前时刻,处于用户态的运行时间,不包含 nice值为负进程。;
     * nice(85733)从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间;
     * system (197165)从系统启动开始累计到当前时刻,处于核心态的运行时间;
     * idle (1328127)从系统启动开始累计到当前时刻,除IO等待时间以外的其它等待时间;
     * iowait(11679)从系统启动开始累计到当前时刻,IO等待时间;
     * softirq (5138)从系统启动开始累计到当前时刻,软中断时间。
     * irq (5)从系统启动开始累计到当前时刻,硬中断时间;
     * @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;
    }

    /**
     * 获取应用占用的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;
    }

    /**
     * 获取当前内存的使用量
     */
    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插入数据代码实现和插入结果统计


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);
}
插入数量 CPU峰值 内存消耗 CPU时间
10条 17.37% 0 30
20条 16.17% 0 57
100条 13.16% 0 270
1000条 11.46% 0 2663

Realm插入数据代码实现和插入结果统计


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);
        }
    });
}
插入数量 CPU峰值 内存消耗 CPU时间
10条 15.95% 0 38
20条 16.46% 0 65
100条 13.26% 0 277
1000条 13.53% 0 2735

从上图得出的结论

  • Realm与GreenDao消耗CPU,内存和时间都差不多

10次的查询的平均资源消耗

GreenDao查询数据代码实现和查询结果统计


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

    if (list != null && list.size() >= 0) {
        localList.addAll(list);
    }
}
查询数量 CPU峰值 内存消耗 CPU时间
10条 31.67% 0 172
20条 30.34% 0 328
100条 27.35% 0 1619
1000条 25.71% 0 16121

Realm查询数据代码实现和查询结果统计


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

            if (realms == null) {
                return;
            }
            counts[0] += realms.size();
        }
    });
}
查询数量 CPU峰值 内存消耗 CPU时间
10条 21.35% 0 75
20条 20.46% 0 145
100条 20.35% 0 723
1000条 19.95% 0 7028

从上图得出的结论

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

10次的删除平均资源消耗

GreenDao删除数据代码实现和删除结果统计


for (int index = 0; index < deleteTimes; index ++) {
    getUserDao().delete(userIds.get(index));
    userIds.remove(index);
}
删除数量 CPU峰值 内存消耗 CPU时间
10条 15.99% 0 41
20条 16.68% 0 76
100条 15.17% 0 371
1000条 15% 0 2771

Realm删除数据代码实现和删除结果统计


for (int index = 0; index < deleteCount; index ++) {
    Realm.getDefaultInstance().executeTransaction(new Realm.Transaction() {
        @Override
        public void execute(Realm realm) {
            RealmResults<Contact> 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();
        }
    });
}
删除数量 CPU峰值 内存消耗 CPU时间
10条 23.13% 0 229
20条 21.56% 0 426
100条 20.45% 0 1729
1000条 17.04% 0 3359

从上图得出的结论

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

10次的更新平均资源消耗

GreenDao删除数据代码实现和删除结果统计

for (int index = 0; index < deleteTimes; index ++) {
    User user = userIds.get(index);
    user.setName(user.getName() + "_____________NEW");
    getUserDao().update(user);
}
更新数量 CPU峰值 内存消耗 CPU时间
10条 13.81% 0 20
20条 14.96% 0 43
100条 14.04% 0 207
1000条 12.18% 0 1546

Realm删除数据代码实现和删除结果统计



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");
        }
    });
}
更新数量 CPU峰值 内存消耗 CPU时间
10条 14.93% 0 30
20条 16.24% 0 57
100条 16.07% 0 277
1000条 14.94% 0 3121

从上图得出的结论

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

综上所述

  • 插入1000条以内的数据时,Realm与GreenDao不分伯仲
  • 查询操作比较频繁,就使用Realm
  • 删除和更新操作比较频繁,就使用GreenDao

    需要说明的是使用Realm的话,打包成apk后,大概会大4M左右,而GreenDao几乎不会导致安装包有太大的变化。但是Realm对于内存优化非常好,号称是Zero-copy

本文来自网易实践者社区,经作者陈杜成授权发布。