├── .gitignore
├── CONTRIBUTING.md
├── GreenDAO-Generator
├── build.gradle
└── src
│ └── com
│ └── littleinc
│ └── orm_benchmark
│ └── greendao
│ └── Generator.java
├── LICENSE.txt
├── ORM-Benchmark
├── build.gradle
├── lint.xml
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── littleinc
│ │ └── orm_benchmark
│ │ ├── BenchmarkExecutable.java
│ │ ├── MainActivity.java
│ │ ├── greendao
│ │ ├── DaoMaster.java
│ │ ├── DaoSession.java
│ │ ├── DataBaseHelper.java
│ │ ├── GreenDaoExecutor.java
│ │ ├── Message.java
│ │ ├── MessageDao.java
│ │ ├── User.java
│ │ └── UserDao.java
│ │ ├── ormlite
│ │ ├── Contact.java
│ │ ├── DataBaseHelper.java
│ │ ├── Message.java
│ │ ├── ORMLiteExecutor.java
│ │ ├── User.java
│ │ └── config
│ │ │ └── DBConfigUtil.java
│ │ ├── sqlite
│ │ ├── DataBaseHelper.java
│ │ ├── Message.java
│ │ ├── SQLiteExecutor.java
│ │ └── User.java
│ │ ├── sqliteoptimized
│ │ ├── DataBaseHelper.java
│ │ ├── OptimizedMessage.java
│ │ ├── OptimizedSQLiteExecutor.java
│ │ └── OptimizedUser.java
│ │ └── util
│ │ └── Util.java
│ └── res
│ ├── drawable-hdpi
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ └── ic_launcher.png
│ ├── layout
│ └── activity_main.xml
│ ├── raw
│ └── ormlite_config.txt
│ ├── values-sw600dp
│ └── dimens.xml
│ ├── values-sw720dp-land
│ └── dimens.xml
│ ├── values-v11
│ └── styles.xml
│ ├── values-v14
│ └── styles.xml
│ └── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── README.md
├── build.gradle
├── screenshots
├── main.png
└── results.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.gitignore.io
2 |
3 | ### Android ###
4 | # Built application files
5 | *.apk
6 | *.ap_
7 |
8 | # Files for the Dalvik VM
9 | *.dex
10 |
11 | # Java class files
12 | *.class
13 |
14 | # Generated files
15 | bin/
16 | gen/
17 |
18 | # Gradle files
19 | .gradle/
20 | build/
21 | /*/build/
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Log Files
30 | *.log
31 |
32 | ### Android Patch ###
33 | gen-external-apklibs
34 |
35 |
36 | ### Intellij ###
37 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
38 |
39 | *.iml
40 |
41 | ## Directory-based project format:
42 | .idea/
43 | # if you remove the above rule, at least ignore the following:
44 |
45 | # User-specific stuff:
46 | # .idea/workspace.xml
47 | # .idea/tasks.xml
48 | # .idea/dictionaries
49 |
50 | # Sensitive or high-churn files:
51 | # .idea/dataSources.ids
52 | # .idea/dataSources.xml
53 | # .idea/sqlDataSources.xml
54 | # .idea/dynamic.xml
55 | # .idea/uiDesigner.xml
56 |
57 | # Gradle:
58 | # .idea/gradle.xml
59 | # .idea/libraries
60 |
61 | # Mongo Explorer plugin:
62 | # .idea/mongoSettings.xml
63 |
64 | ## File-based project format:
65 | *.ipr
66 | *.iws
67 |
68 | ## Plugin-specific files:
69 |
70 | # IntelliJ
71 | out/
72 |
73 | # mpeltonen/sbt-idea plugin
74 | .idea_modules/
75 |
76 | # JIRA plugin
77 | atlassian-ide-plugin.xml
78 |
79 | # Crashlytics plugin (for Android Studio and IntelliJ)
80 | com_crashlytics_export_strings.xml
81 | crashlytics.properties
82 | crashlytics-build.properties
83 |
84 |
85 | ### Gradle ###
86 | .gradle
87 | build/
88 |
89 | # Ignore Gradle GUI config
90 | gradle-app.setting
91 |
92 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
93 | !gradle-wrapper.jar
94 |
95 |
96 | ### Java ###
97 | *.class
98 |
99 | # Mobile Tools for Java (J2ME)
100 | .mtj.tmp/
101 |
102 | # Package Files #
103 | *.jar
104 | *.war
105 | *.ear
106 |
107 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
108 | hs_err_pid*
109 |
110 |
111 | ### OSX ###
112 | .DS_Store
113 | .AppleDouble
114 | .LSOverride
115 |
116 | # Icon must end with two \r
117 | Icon
118 |
119 |
120 | # Thumbnails
121 | ._*
122 |
123 | # Files that might appear on external disk
124 | .Spotlight-V100
125 | .Trashes
126 |
127 | # Directories potentially created on remote AFP share
128 | .AppleDB
129 | .AppleDesktop
130 | Network Trash Folder
131 | Temporary Items
132 | .apdisk
133 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | If you would like to contribute code you can do so through GitHub by forking
5 | the repository and sending a pull request.
6 |
7 | When submitting code, please make every effort to follow existing conventions
8 | and style in order to keep the code as readable as possible.
--------------------------------------------------------------------------------
/GreenDAO-Generator/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 |
3 | dependencies {
4 | compile fileTree(dir: 'libs', include: ['*.jar'])
5 |
6 | compile 'de.greenrobot:greendao-generator:1.3.1'
7 | }
--------------------------------------------------------------------------------
/GreenDAO-Generator/src/com/littleinc/orm_benchmark/greendao/Generator.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import de.greenrobot.daogenerator.DaoGenerator;
4 | import de.greenrobot.daogenerator.Entity;
5 | import de.greenrobot.daogenerator.Property;
6 | import de.greenrobot.daogenerator.Schema;
7 |
8 | public class Generator {
9 |
10 | // DB CONFIG
11 | private static int DB_VERSION = 2;
12 |
13 | private static String PACKAGE = "com.littleinc.orm_benchmark.greendao";
14 |
15 | // USER TABLE
16 | private static final String USER_ENTITY = "User";
17 |
18 | public static final String LAST_NAME_COLUMN = "last_name";
19 |
20 | public static final String FIRST_NAME_COLUMN = "first_name";
21 |
22 | // MESSAGE TABLE
23 | private static final String MESSAGE_ENTITY = "Message";
24 |
25 | private static final String CONTENT = "content";
26 |
27 | private static final String READERS = "readers";
28 |
29 | private static final String SORTED_BY = "sorted_by";
30 |
31 | private static final String CLIENT_ID = "client_id";
32 |
33 | private static final String SENDER_ID = "sender_id";
34 |
35 | private static final String CHANNEL_ID = "channel_id";
36 |
37 | private static final String COMMAND_ID = "command_id";
38 |
39 | private static final String CREATED_AT = "created_at";
40 |
41 | public static void main(String[] args) {
42 | Schema schema = new Schema(DB_VERSION, PACKAGE);
43 |
44 | Entity user = schema.addEntity(USER_ENTITY);
45 | Property userPk = addCommonColumns(user);
46 |
47 | Entity message = schema.addEntity(MESSAGE_ENTITY);
48 | message.addIdProperty().autoincrement();
49 | message.addStringProperty(CONTENT);
50 | message.addLongProperty(CLIENT_ID);
51 | message.addIntProperty(CREATED_AT);
52 | message.addDoubleProperty(SORTED_BY);
53 | message.addLongProperty(COMMAND_ID).index();
54 | message.addLongProperty(SENDER_ID).notNull();
55 | message.addLongProperty(CHANNEL_ID).notNull();
56 |
57 | // One-to-many relationship
58 | message.addToMany(user, userPk, READERS);
59 |
60 | try {
61 | new DaoGenerator().generateAll(schema, "../ORM-Benchmark/src/");
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 | }
66 |
67 | private static Property addCommonColumns(Entity entity) {
68 | entity.addStringProperty(LAST_NAME_COLUMN);
69 | entity.addStringProperty(FIRST_NAME_COLUMN);
70 | return entity.addIdProperty().autoincrement().getProperty();
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/ORM-Benchmark/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21"
6 |
7 | defaultConfig {
8 | applicationId "com.littleinc.orm_benchmark"
9 | minSdkVersion 9
10 | targetSdkVersion 21
11 | }
12 |
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile 'com.android.support:support-v4:21.+'
23 |
24 | compile 'de.greenrobot:greendao:1.3.7'
25 | compile 'com.j256.ormlite:ormlite-core:4.48'
26 | compile 'com.j256.ormlite:ormlite-android:4.48'
27 | }
--------------------------------------------------------------------------------
/ORM-Benchmark/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark;
2 |
3 | import java.sql.SQLException;
4 |
5 | import android.content.Context;
6 |
7 | public interface BenchmarkExecutable {
8 |
9 | String SEARCH_TERM = "a";
10 |
11 | long SEARCH_LIMIT = 100;
12 |
13 | int NUM_READERS = 10;
14 |
15 | int NUM_USER_INSERTS = 1000;
16 |
17 | int NUM_MESSAGE_INSERTS = 10000;
18 |
19 | int NUM_MESSAGES_WITH_READERS = 50;
20 |
21 | int LOOK_BY_INDEXED_FIELD = 5000;
22 |
23 | enum Task {
24 | CREATE_DB, WRITE_DATA, READ_DATA, READ_INDEXED, READ_SEARCH, DROP_DB;
25 | }
26 |
27 | String getOrmName();
28 |
29 | void init(Context context, boolean useInMemoryDb);
30 |
31 | long createDbStructure() throws SQLException;
32 |
33 | long writeWholeData() throws SQLException;
34 |
35 | long readWholeData() throws SQLException;
36 |
37 | long readIndexedField() throws SQLException;
38 |
39 | long readSearch() throws SQLException;
40 |
41 | long dropDb() throws SQLException;
42 | }
43 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark;
2 |
3 | import static com.littleinc.orm_benchmark.BenchmarkExecutable.Task.CREATE_DB;
4 | import static com.littleinc.orm_benchmark.BenchmarkExecutable.Task.DROP_DB;
5 | import static com.littleinc.orm_benchmark.BenchmarkExecutable.Task.READ_DATA;
6 | import static com.littleinc.orm_benchmark.BenchmarkExecutable.Task.READ_INDEXED;
7 | import static com.littleinc.orm_benchmark.BenchmarkExecutable.Task.READ_SEARCH;
8 | import static com.littleinc.orm_benchmark.BenchmarkExecutable.Task.WRITE_DATA;
9 |
10 | import java.sql.SQLException;
11 | import java.util.HashMap;
12 | import java.util.LinkedList;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | import android.app.AlertDialog;
17 | import android.app.Dialog;
18 | import android.os.AsyncTask;
19 | import android.os.Bundle;
20 | import android.support.v4.app.DialogFragment;
21 | import android.support.v4.app.FragmentActivity;
22 | import android.support.v4.app.FragmentTransaction;
23 | import android.text.Html;
24 | import android.util.Log;
25 | import android.util.SparseArray;
26 | import android.view.View;
27 | import android.widget.Button;
28 |
29 | import com.littleinc.orm_benchmark.BenchmarkExecutable.Task;
30 | import com.littleinc.orm_benchmark.greendao.GreenDaoExecutor;
31 | import com.littleinc.orm_benchmark.ormlite.ORMLiteExecutor;
32 | import com.littleinc.orm_benchmark.sqlite.SQLiteExecutor;
33 | import com.littleinc.orm_benchmark.sqliteoptimized.OptimizedSQLiteExecutor;
34 | import com.littleinc.orm_benchmark.util.Util;
35 |
36 | public class MainActivity extends FragmentActivity {
37 |
38 | private static final boolean USE_IN_MEMORY_DB = true;
39 |
40 | private static final int NUM_ITERATIONS = 5;
41 |
42 | private int mCount = 0;
43 |
44 | private String mResults;
45 |
46 | private Button mShowResultsBtn;
47 |
48 | private BenchmarkExecutable[] mOrms = new BenchmarkExecutable[] {
49 | new SQLiteExecutor(),
50 | new OptimizedSQLiteExecutor(),
51 | new ORMLiteExecutor(),
52 | new GreenDaoExecutor() };
53 |
54 | private boolean mWasInitialized = false;
55 |
56 | private Map>> mGlobalResults;
57 |
58 | @Override
59 | protected void onCreate(Bundle savedInstanceState) {
60 | super.onCreate(savedInstanceState);
61 | setContentView(R.layout.activity_main);
62 |
63 | mGlobalResults = new HashMap<>();
64 | mShowResultsBtn = (Button) findViewById(R.id.show_results_btn);
65 |
66 | if (!mWasInitialized) {
67 | for (BenchmarkExecutable orm : mOrms) {
68 | orm.init(this, USE_IN_MEMORY_DB);
69 | }
70 |
71 | mWasInitialized = true;
72 | }
73 | }
74 |
75 | public void showGlobalResults(View v) {
76 | ResultDialog dialog = ResultDialog.newInstance(R.string.results_title, mResults);
77 | FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
78 | tx.add(dialog, ResultDialog.class.getSimpleName());
79 | tx.commit();
80 | }
81 |
82 | public void runBenchmark(View v) {
83 | if (mCount < NUM_ITERATIONS) {
84 | v.setEnabled(false);
85 | mShowResultsBtn.setEnabled(false);
86 |
87 | new ProfilerTask(v).execute(
88 | CREATE_DB,
89 | WRITE_DATA,
90 | READ_DATA,
91 | READ_INDEXED,
92 | READ_SEARCH,
93 | DROP_DB);
94 | } else {
95 | mResults = buildResults();
96 | Log.d(MainActivity.class.getSimpleName(), "Results:\n" + mResults);
97 |
98 | mCount = 0;
99 | v.setEnabled(true);
100 | mShowResultsBtn.setEnabled(true);
101 | }
102 | }
103 |
104 | private String buildResults() {
105 | StringBuilder builder = new StringBuilder();
106 | tasks: for (Task task : Task.values()) {
107 | builder.append("Task ").append(task).append(" ");
108 | orms: for (BenchmarkExecutable orm : mOrms) {
109 |
110 | Map> results = mGlobalResults.get(orm.getOrmName());
111 |
112 | if (results == null) {
113 | continue orms;
114 | }
115 | List resultsPerTask = results.get(task);
116 | if (resultsPerTask == null) {
117 | continue tasks;
118 | }
119 | int numExecutions = resultsPerTask.size();
120 | long resultsCount = 0;
121 | for (Long result : resultsPerTask) {
122 | resultsCount += result;
123 | }
124 | builder.append(orm.getOrmName())
125 | .append(" - Avg: ")
126 | .append(Util.formatElapsedTime(resultsCount
127 | / numExecutions)).append(" ");
128 | }
129 | builder.append(" ");
130 | }
131 | return builder.toString();
132 | }
133 |
134 | private class ProfilerTask extends AsyncTask {
135 |
136 | private View mView;
137 |
138 | public ProfilerTask(View v) {
139 | mView = v;
140 | }
141 |
142 | @Override
143 | protected Void doInBackground(Task... params) {
144 | for (BenchmarkExecutable item : mOrms) {
145 | for (Task task : params) {
146 | try {
147 | long result = 0;
148 |
149 | switch (task) {
150 | case CREATE_DB:
151 | result = item.createDbStructure();
152 | break;
153 | case DROP_DB:
154 | result = item.dropDb();
155 | break;
156 | case READ_DATA:
157 | result = item.readWholeData();
158 | break;
159 | case READ_INDEXED:
160 | result = item.readIndexedField();
161 | break;
162 | case READ_SEARCH:
163 | result = item.readSearch();
164 | break;
165 | case WRITE_DATA:
166 | result = item.writeWholeData();
167 | break;
168 | }
169 | addProfilerResult(item.getOrmName(), task, result);
170 | } catch (SQLException e) {
171 | e.printStackTrace();
172 | continue;
173 | }
174 | }
175 | }
176 | return null;
177 | }
178 |
179 | protected void onPostExecute(Void result) {
180 | mCount++;
181 | runBenchmark(mView);
182 | };
183 |
184 | private void addProfilerResult(String benchmarkName, Task task, long result) {
185 | Map> profilerResults = mGlobalResults.get(benchmarkName);
186 | if (profilerResults == null) {
187 | profilerResults = new HashMap<>();
188 | profilerResults.put(task, new LinkedList());
189 | mGlobalResults.put(benchmarkName, profilerResults);
190 | }
191 | List resultPerTask = profilerResults.get(task);
192 | if (resultPerTask == null) {
193 | resultPerTask = new LinkedList<>();
194 | profilerResults.put(task, resultPerTask);
195 | }
196 | resultPerTask.add(result);
197 | }
198 | }
199 |
200 | public static class ResultDialog extends DialogFragment {
201 |
202 | private static String TITLE_RES_ID = "title_res_id";
203 |
204 | private static String MESSAGE = "message";
205 |
206 | public static ResultDialog newInstance(int titleResId, String message) {
207 | ResultDialog dialog = new ResultDialog();
208 |
209 | Bundle args = new Bundle();
210 | args.putString(MESSAGE, message);
211 | args.putInt(TITLE_RES_ID, titleResId);
212 | dialog.setArguments(args);
213 |
214 | return dialog;
215 | }
216 |
217 | @Override
218 | public Dialog onCreateDialog(Bundle savedInstanceState) {
219 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
220 | return builder
221 | .setTitle(getArguments().getInt(TITLE_RES_ID))
222 | .setMessage(Html.fromHtml(getArguments().getString(MESSAGE)))
223 | .create();
224 | }
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/DaoMaster.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteDatabase.CursorFactory;
6 | import android.database.sqlite.SQLiteOpenHelper;
7 | import android.util.Log;
8 | import de.greenrobot.dao.AbstractDaoMaster;
9 | import de.greenrobot.dao.identityscope.IdentityScopeType;
10 |
11 | import com.littleinc.orm_benchmark.greendao.UserDao;
12 | import com.littleinc.orm_benchmark.greendao.MessageDao;
13 |
14 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
15 | /**
16 | * Master of DAO (schema version 2): knows all DAOs.
17 | */
18 | public class DaoMaster extends AbstractDaoMaster {
19 | public static final int SCHEMA_VERSION = 2;
20 |
21 | /** Creates underlying database table using DAOs. */
22 | public static void createAllTables(SQLiteDatabase db, boolean ifNotExists) {
23 | UserDao.createTable(db, ifNotExists);
24 | MessageDao.createTable(db, ifNotExists);
25 | }
26 |
27 | /** Drops underlying database table using DAOs. */
28 | public static void dropAllTables(SQLiteDatabase db, boolean ifExists) {
29 | UserDao.dropTable(db, ifExists);
30 | MessageDao.dropTable(db, ifExists);
31 | }
32 |
33 | public static abstract class OpenHelper extends SQLiteOpenHelper {
34 |
35 | public OpenHelper(Context context, String name, CursorFactory factory) {
36 | super(context, name, factory, SCHEMA_VERSION);
37 | }
38 |
39 | @Override
40 | public void onCreate(SQLiteDatabase db) {
41 | Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION);
42 | createAllTables(db, false);
43 | }
44 | }
45 |
46 | /** WARNING: Drops all table on Upgrade! Use only during development. */
47 | public static class DevOpenHelper extends OpenHelper {
48 | public DevOpenHelper(Context context, String name, CursorFactory factory) {
49 | super(context, name, factory);
50 | }
51 |
52 | @Override
53 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
54 | Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
55 | dropAllTables(db, true);
56 | onCreate(db);
57 | }
58 | }
59 |
60 | public DaoMaster(SQLiteDatabase db) {
61 | super(db, SCHEMA_VERSION);
62 | registerDaoClass(UserDao.class);
63 | registerDaoClass(MessageDao.class);
64 | }
65 |
66 | public DaoSession newSession() {
67 | return new DaoSession(db, IdentityScopeType.Session, daoConfigMap);
68 | }
69 |
70 | public DaoSession newSession(IdentityScopeType type) {
71 | return new DaoSession(db, type, daoConfigMap);
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/DaoSession.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import android.database.sqlite.SQLiteDatabase;
4 |
5 | import java.util.Map;
6 |
7 | import de.greenrobot.dao.AbstractDao;
8 | import de.greenrobot.dao.AbstractDaoSession;
9 | import de.greenrobot.dao.identityscope.IdentityScopeType;
10 | import de.greenrobot.dao.internal.DaoConfig;
11 |
12 | import com.littleinc.orm_benchmark.greendao.User;
13 | import com.littleinc.orm_benchmark.greendao.Message;
14 |
15 | import com.littleinc.orm_benchmark.greendao.UserDao;
16 | import com.littleinc.orm_benchmark.greendao.MessageDao;
17 |
18 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
19 |
20 | /**
21 | * {@inheritDoc}
22 | *
23 | * @see de.greenrobot.dao.AbstractDaoSession
24 | */
25 | public class DaoSession extends AbstractDaoSession {
26 |
27 | private final DaoConfig userDaoConfig;
28 | private final DaoConfig messageDaoConfig;
29 |
30 | private final UserDao userDao;
31 | private final MessageDao messageDao;
32 |
33 | public DaoSession(SQLiteDatabase db, IdentityScopeType type, Map>, DaoConfig>
34 | daoConfigMap) {
35 | super(db);
36 |
37 | userDaoConfig = daoConfigMap.get(UserDao.class).clone();
38 | userDaoConfig.initIdentityScope(type);
39 |
40 | messageDaoConfig = daoConfigMap.get(MessageDao.class).clone();
41 | messageDaoConfig.initIdentityScope(type);
42 |
43 | userDao = new UserDao(userDaoConfig, this);
44 | messageDao = new MessageDao(messageDaoConfig, this);
45 |
46 | registerDao(User.class, userDao);
47 | registerDao(Message.class, messageDao);
48 | }
49 |
50 | public void clear() {
51 | userDaoConfig.getIdentityScope().clear();
52 | messageDaoConfig.getIdentityScope().clear();
53 | }
54 |
55 | public UserDao getUserDao() {
56 | return userDao;
57 | }
58 |
59 | public MessageDao getMessageDao() {
60 | return messageDao;
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/DataBaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteDatabase.CursorFactory;
6 |
7 | import com.littleinc.orm_benchmark.greendao.DaoMaster.DevOpenHelper;
8 |
9 | public class DataBaseHelper extends DevOpenHelper {
10 |
11 | public DataBaseHelper(Context context, String name, CursorFactory factory) {
12 | super(context, name, factory);
13 | }
14 |
15 | @Override
16 | public void onCreate(SQLiteDatabase db) {
17 | super.onCreate(db);
18 | }
19 |
20 | @Override
21 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
22 | super.onUpgrade(db, oldVersion, newVersion);
23 | }
24 |
25 | @Override
26 | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
27 | super.onDowngrade(db, oldVersion, newVersion);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/GreenDaoExecutor.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import static com.littleinc.orm_benchmark.util.Util.getRandomString;
4 |
5 | import java.sql.SQLException;
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 | import android.content.Context;
10 | import android.util.Log;
11 |
12 | import com.littleinc.orm_benchmark.BenchmarkExecutable;
13 | import com.littleinc.orm_benchmark.greendao.MessageDao.Properties;
14 | import com.littleinc.orm_benchmark.util.Util;
15 |
16 | public class GreenDaoExecutor implements BenchmarkExecutable {
17 |
18 | private static final String TAG = "GreenDaoExecutor";
19 |
20 | private static String DB_NAME = "greendao_db";
21 |
22 | private DataBaseHelper mHelper;
23 |
24 | private DaoMaster mDaoMaster;
25 |
26 | @Override
27 | public void init(Context context, boolean useInMemoryDb) {
28 | Log.d(TAG, "Creating DataBaseHelper");
29 | mHelper = new DataBaseHelper(context, (useInMemoryDb ? null : DB_NAME),
30 | null);
31 | }
32 |
33 | @Override
34 | public long createDbStructure() throws SQLException {
35 | long start = System.nanoTime();
36 | if (mDaoMaster == null) {
37 | mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());
38 | } else {
39 | DaoMaster.createAllTables(mHelper.getWritableDatabase(), true);
40 | }
41 | return System.nanoTime() - start;
42 | }
43 |
44 | @Override
45 | public long writeWholeData() throws SQLException {
46 | final List users = new LinkedList();
47 | for (int i = 0; i < NUM_USER_INSERTS; i++) {
48 | User newUser = new User(getRandomString(10), getRandomString(10),
49 | null);
50 | users.add(newUser);
51 | }
52 |
53 | final List messages = new LinkedList();
54 | for (long i = 0; i < NUM_MESSAGE_INSERTS; i++) {
55 | Message newMessage = new Message(null);
56 | newMessage.setCommand_id(i);
57 | newMessage.setSorted_by(Double.valueOf(System.nanoTime()));
58 | newMessage.setContent(Util.getRandomString(100));
59 | newMessage.setClient_id(System.currentTimeMillis());
60 | newMessage.setSender_id(Math.round(Math.random() * NUM_USER_INSERTS));
61 | newMessage.setChannel_id(Math.round(Math.random() * NUM_USER_INSERTS));
62 | newMessage.setCreated_at((int) (System.currentTimeMillis() / 1000L));
63 |
64 | messages.add(newMessage);
65 | }
66 |
67 | long start = System.nanoTime();
68 | final DaoSession daoSession = mDaoMaster.newSession();
69 | daoSession.runInTx(new Runnable() {
70 |
71 | @Override
72 | public void run() {
73 | UserDao userDao = daoSession.getUserDao();
74 | for (User user : users) {
75 | userDao.insertOrReplace(user);
76 | }
77 | Log.d(GreenDaoExecutor.class.getSimpleName(), "Done, wrote "
78 | + NUM_USER_INSERTS + " users");
79 |
80 | MessageDao messageDao = daoSession.getMessageDao();
81 | for (Message message : messages) {
82 | messageDao.insertOrReplace(message);
83 | }
84 | Log.d(GreenDaoExecutor.class.getSimpleName(), "Done, wrote "
85 | + NUM_MESSAGE_INSERTS + " messages");
86 | daoSession.clear();
87 | }
88 | });
89 | return System.nanoTime() - start;
90 | }
91 |
92 | @Override
93 | public long readWholeData() throws SQLException {
94 | long start = System.nanoTime();
95 | DaoSession daoSession = mDaoMaster.newSession();
96 | MessageDao messageDao = daoSession.getMessageDao();
97 | Log.d(GreenDaoExecutor.class.getSimpleName(), "Read, "
98 | + messageDao.queryBuilder().list().size() + " rows");
99 | daoSession.clear();
100 | return System.nanoTime() - start;
101 | }
102 |
103 | @Override
104 | public long readIndexedField() throws SQLException {
105 | long start = System.nanoTime();
106 | DaoSession daoSession = mDaoMaster.newSession();
107 | MessageDao messageDao = daoSession.getMessageDao();
108 | Log.d(GreenDaoExecutor.class.getSimpleName(),
109 | "Read, "
110 | + messageDao
111 | .queryBuilder()
112 | .where(Properties.Command_id
113 | .eq(LOOK_BY_INDEXED_FIELD)).list()
114 | .size() + " rows");
115 | daoSession.clear();
116 | return System.nanoTime() - start;
117 | }
118 |
119 | @Override
120 | public long readSearch() throws SQLException {
121 | long start = System.nanoTime();
122 | DaoSession daoSession = mDaoMaster.newSession();
123 | MessageDao messageDao = daoSession.getMessageDao();
124 | Log.d(GreenDaoExecutor.class.getSimpleName(),
125 | "Read, "
126 | + messageDao
127 | .queryBuilder()
128 | .limit((int) SEARCH_LIMIT)
129 | .where(Properties.Content.like("%"
130 | + SEARCH_TERM + "%")).list().size()
131 | + " rows");
132 | daoSession.clear();
133 | return System.nanoTime() - start;
134 | }
135 |
136 | @Override
137 | public long dropDb() throws SQLException {
138 | long start = System.nanoTime();
139 | DaoMaster.dropAllTables(mHelper.getWritableDatabase(), true);
140 | return System.nanoTime() - start;
141 | }
142 |
143 | @Override
144 | public String getOrmName() {
145 | return "GreenDAO";
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/Message.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import java.util.List;
4 | import com.littleinc.orm_benchmark.greendao.DaoSession;
5 | import de.greenrobot.dao.DaoException;
6 |
7 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. Enable "keep" sections if you want to edit.
8 | /**
9 | * Entity mapped to table MESSAGE.
10 | */
11 | public class Message {
12 |
13 | private Long id;
14 | private String content;
15 | private Long client_id;
16 | private Integer created_at;
17 | private Double sorted_by;
18 | private Long command_id;
19 | private long sender_id;
20 | private long channel_id;
21 |
22 | /** Used to resolve relations */
23 | private transient DaoSession daoSession;
24 |
25 | /** Used for active entity operations. */
26 | private transient MessageDao myDao;
27 |
28 | private List readers;
29 |
30 | public Message() {
31 | }
32 |
33 | public Message(Long id) {
34 | this.id = id;
35 | }
36 |
37 | public Message(Long id, String content, Long client_id, Integer created_at, Double sorted_by, Long command_id, long sender_id, long channel_id) {
38 | this.id = id;
39 | this.content = content;
40 | this.client_id = client_id;
41 | this.created_at = created_at;
42 | this.sorted_by = sorted_by;
43 | this.command_id = command_id;
44 | this.sender_id = sender_id;
45 | this.channel_id = channel_id;
46 | }
47 |
48 | /** called by internal mechanisms, do not call yourself. */
49 | public void __setDaoSession(DaoSession daoSession) {
50 | this.daoSession = daoSession;
51 | myDao = daoSession != null ? daoSession.getMessageDao() : null;
52 | }
53 |
54 | public Long getId() {
55 | return id;
56 | }
57 |
58 | public void setId(Long id) {
59 | this.id = id;
60 | }
61 |
62 | public String getContent() {
63 | return content;
64 | }
65 |
66 | public void setContent(String content) {
67 | this.content = content;
68 | }
69 |
70 | public Long getClient_id() {
71 | return client_id;
72 | }
73 |
74 | public void setClient_id(Long client_id) {
75 | this.client_id = client_id;
76 | }
77 |
78 | public Integer getCreated_at() {
79 | return created_at;
80 | }
81 |
82 | public void setCreated_at(Integer created_at) {
83 | this.created_at = created_at;
84 | }
85 |
86 | public Double getSorted_by() {
87 | return sorted_by;
88 | }
89 |
90 | public void setSorted_by(Double sorted_by) {
91 | this.sorted_by = sorted_by;
92 | }
93 |
94 | public Long getCommand_id() {
95 | return command_id;
96 | }
97 |
98 | public void setCommand_id(Long command_id) {
99 | this.command_id = command_id;
100 | }
101 |
102 | public long getSender_id() {
103 | return sender_id;
104 | }
105 |
106 | public void setSender_id(long sender_id) {
107 | this.sender_id = sender_id;
108 | }
109 |
110 | public long getChannel_id() {
111 | return channel_id;
112 | }
113 |
114 | public void setChannel_id(long channel_id) {
115 | this.channel_id = channel_id;
116 | }
117 |
118 | /** To-many relationship, resolved on first access (and after reset). Changes to to-many relations are not persisted, make changes to the target entity. */
119 | public List getReaders() {
120 | if (readers == null) {
121 | if (daoSession == null) {
122 | throw new DaoException("Entity is detached from DAO context");
123 | }
124 | UserDao targetDao = daoSession.getUserDao();
125 | List readersNew = targetDao._queryMessage_Readers(id);
126 | synchronized (this) {
127 | if(readers == null) {
128 | readers = readersNew;
129 | }
130 | }
131 | }
132 | return readers;
133 | }
134 |
135 | /** Resets a to-many relationship, making the next get call to query for a fresh result. */
136 | public synchronized void resetReaders() {
137 | readers = null;
138 | }
139 |
140 | /** Convenient call for {@link AbstractDao#delete(Object)}. Entity must attached to an entity context. */
141 | public void delete() {
142 | if (myDao == null) {
143 | throw new DaoException("Entity is detached from DAO context");
144 | }
145 | myDao.delete(this);
146 | }
147 |
148 | /** Convenient call for {@link AbstractDao#update(Object)}. Entity must attached to an entity context. */
149 | public void update() {
150 | if (myDao == null) {
151 | throw new DaoException("Entity is detached from DAO context");
152 | }
153 | myDao.update(this);
154 | }
155 |
156 | /** Convenient call for {@link AbstractDao#refresh(Object)}. Entity must attached to an entity context. */
157 | public void refresh() {
158 | if (myDao == null) {
159 | throw new DaoException("Entity is detached from DAO context");
160 | }
161 | myDao.refresh(this);
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/MessageDao.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import android.database.Cursor;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteStatement;
6 |
7 | import de.greenrobot.dao.AbstractDao;
8 | import de.greenrobot.dao.Property;
9 | import de.greenrobot.dao.internal.DaoConfig;
10 |
11 | import com.littleinc.orm_benchmark.greendao.Message;
12 |
13 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
14 | /**
15 | * DAO for table MESSAGE.
16 | */
17 | public class MessageDao extends AbstractDao {
18 |
19 | public static final String TABLENAME = "MESSAGE";
20 |
21 | /**
22 | * Properties of entity Message.
23 | * Can be used for QueryBuilder and for referencing column names.
24 | */
25 | public static class Properties {
26 | public final static Property Id = new Property(0, Long.class, "id", true, "_id");
27 | public final static Property Content = new Property(1, String.class, "content", false, "CONTENT");
28 | public final static Property Client_id = new Property(2, Long.class, "client_id", false, "CLIENT_ID");
29 | public final static Property Created_at = new Property(3, Integer.class, "created_at", false, "CREATED_AT");
30 | public final static Property Sorted_by = new Property(4, Double.class, "sorted_by", false, "SORTED_BY");
31 | public final static Property Command_id = new Property(5, Long.class, "command_id", false, "COMMAND_ID");
32 | public final static Property Sender_id = new Property(6, long.class, "sender_id", false, "SENDER_ID");
33 | public final static Property Channel_id = new Property(7, long.class, "channel_id", false, "CHANNEL_ID");
34 | };
35 |
36 | private DaoSession daoSession;
37 |
38 |
39 | public MessageDao(DaoConfig config) {
40 | super(config);
41 | }
42 |
43 | public MessageDao(DaoConfig config, DaoSession daoSession) {
44 | super(config, daoSession);
45 | this.daoSession = daoSession;
46 | }
47 |
48 | /** Creates the underlying database table. */
49 | public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
50 | String constraint = ifNotExists? "IF NOT EXISTS ": "";
51 | db.execSQL("CREATE TABLE " + constraint + "'MESSAGE' (" + //
52 | "'_id' INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id
53 | "'CONTENT' TEXT," + // 1: content
54 | "'CLIENT_ID' INTEGER," + // 2: client_id
55 | "'CREATED_AT' INTEGER," + // 3: created_at
56 | "'SORTED_BY' REAL," + // 4: sorted_by
57 | "'COMMAND_ID' INTEGER," + // 5: command_id
58 | "'SENDER_ID' INTEGER NOT NULL ," + // 6: sender_id
59 | "'CHANNEL_ID' INTEGER NOT NULL );"); // 7: channel_id
60 | // Add Indexes
61 | db.execSQL("CREATE INDEX " + constraint + "IDX_MESSAGE_COMMAND_ID ON MESSAGE" +
62 | " (COMMAND_ID);");
63 | }
64 |
65 | /** Drops the underlying database table. */
66 | public static void dropTable(SQLiteDatabase db, boolean ifExists) {
67 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'MESSAGE'";
68 | db.execSQL(sql);
69 | }
70 |
71 | /** @inheritdoc */
72 | @Override
73 | protected void bindValues(SQLiteStatement stmt, Message entity) {
74 | stmt.clearBindings();
75 |
76 | Long id = entity.getId();
77 | if (id != null) {
78 | stmt.bindLong(1, id);
79 | }
80 |
81 | String content = entity.getContent();
82 | if (content != null) {
83 | stmt.bindString(2, content);
84 | }
85 |
86 | Long client_id = entity.getClient_id();
87 | if (client_id != null) {
88 | stmt.bindLong(3, client_id);
89 | }
90 |
91 | Integer created_at = entity.getCreated_at();
92 | if (created_at != null) {
93 | stmt.bindLong(4, created_at);
94 | }
95 |
96 | Double sorted_by = entity.getSorted_by();
97 | if (sorted_by != null) {
98 | stmt.bindDouble(5, sorted_by);
99 | }
100 |
101 | Long command_id = entity.getCommand_id();
102 | if (command_id != null) {
103 | stmt.bindLong(6, command_id);
104 | }
105 | stmt.bindLong(7, entity.getSender_id());
106 | stmt.bindLong(8, entity.getChannel_id());
107 | }
108 |
109 | @Override
110 | protected void attachEntity(Message entity) {
111 | super.attachEntity(entity);
112 | entity.__setDaoSession(daoSession);
113 | }
114 |
115 | /** @inheritdoc */
116 | @Override
117 | public Long readKey(Cursor cursor, int offset) {
118 | return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0);
119 | }
120 |
121 | /** @inheritdoc */
122 | @Override
123 | public Message readEntity(Cursor cursor, int offset) {
124 | Message entity = new Message( //
125 | cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id
126 | cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // content
127 | cursor.isNull(offset + 2) ? null : cursor.getLong(offset + 2), // client_id
128 | cursor.isNull(offset + 3) ? null : cursor.getInt(offset + 3), // created_at
129 | cursor.isNull(offset + 4) ? null : cursor.getDouble(offset + 4), // sorted_by
130 | cursor.isNull(offset + 5) ? null : cursor.getLong(offset + 5), // command_id
131 | cursor.getLong(offset + 6), // sender_id
132 | cursor.getLong(offset + 7) // channel_id
133 | );
134 | return entity;
135 | }
136 |
137 | /** @inheritdoc */
138 | @Override
139 | public void readEntity(Cursor cursor, Message entity, int offset) {
140 | entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0));
141 | entity.setContent(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
142 | entity.setClient_id(cursor.isNull(offset + 2) ? null : cursor.getLong(offset + 2));
143 | entity.setCreated_at(cursor.isNull(offset + 3) ? null : cursor.getInt(offset + 3));
144 | entity.setSorted_by(cursor.isNull(offset + 4) ? null : cursor.getDouble(offset + 4));
145 | entity.setCommand_id(cursor.isNull(offset + 5) ? null : cursor.getLong(offset + 5));
146 | entity.setSender_id(cursor.getLong(offset + 6));
147 | entity.setChannel_id(cursor.getLong(offset + 7));
148 | }
149 |
150 | /** @inheritdoc */
151 | @Override
152 | protected Long updateKeyAfterInsert(Message entity, long rowId) {
153 | entity.setId(rowId);
154 | return rowId;
155 | }
156 |
157 | /** @inheritdoc */
158 | @Override
159 | public Long getKey(Message entity) {
160 | if(entity != null) {
161 | return entity.getId();
162 | } else {
163 | return null;
164 | }
165 | }
166 |
167 | /** @inheritdoc */
168 | @Override
169 | protected boolean isEntityUpdateable() {
170 | return true;
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/User.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. Enable "keep" sections if you want to edit.
4 | /**
5 | * Entity mapped to table USER.
6 | */
7 | public class User {
8 |
9 | private String last_name;
10 | private String first_name;
11 | private Long id;
12 |
13 | public User() {
14 | }
15 |
16 | public User(Long id) {
17 | this.id = id;
18 | }
19 |
20 | public User(String last_name, String first_name, Long id) {
21 | this.last_name = last_name;
22 | this.first_name = first_name;
23 | this.id = id;
24 | }
25 |
26 | public String getLast_name() {
27 | return last_name;
28 | }
29 |
30 | public void setLast_name(String last_name) {
31 | this.last_name = last_name;
32 | }
33 |
34 | public String getFirst_name() {
35 | return first_name;
36 | }
37 |
38 | public void setFirst_name(String first_name) {
39 | this.first_name = first_name;
40 | }
41 |
42 | public Long getId() {
43 | return id;
44 | }
45 |
46 | public void setId(Long id) {
47 | this.id = id;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/greendao/UserDao.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.greendao;
2 |
3 | import java.util.List;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.database.sqlite.SQLiteStatement;
7 |
8 | import de.greenrobot.dao.AbstractDao;
9 | import de.greenrobot.dao.Property;
10 | import de.greenrobot.dao.internal.DaoConfig;
11 | import de.greenrobot.dao.query.Query;
12 | import de.greenrobot.dao.query.QueryBuilder;
13 |
14 | import com.littleinc.orm_benchmark.greendao.User;
15 |
16 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT.
17 | /**
18 | * DAO for table USER.
19 | */
20 | public class UserDao extends AbstractDao {
21 |
22 | public static final String TABLENAME = "USER";
23 |
24 | /**
25 | * Properties of entity User.
26 | * Can be used for QueryBuilder and for referencing column names.
27 | */
28 | public static class Properties {
29 | public final static Property Last_name = new Property(0, String.class, "last_name", false, "LAST_NAME");
30 | public final static Property First_name = new Property(1, String.class, "first_name", false, "FIRST_NAME");
31 | public final static Property Id = new Property(2, Long.class, "id", true, "_id");
32 | };
33 |
34 | private Query message_ReadersQuery;
35 |
36 | public UserDao(DaoConfig config) {
37 | super(config);
38 | }
39 |
40 | public UserDao(DaoConfig config, DaoSession daoSession) {
41 | super(config, daoSession);
42 | }
43 |
44 | /** Creates the underlying database table. */
45 | public static void createTable(SQLiteDatabase db, boolean ifNotExists) {
46 | String constraint = ifNotExists? "IF NOT EXISTS ": "";
47 | db.execSQL("CREATE TABLE " + constraint + "'USER' (" + //
48 | "'LAST_NAME' TEXT," + // 0: last_name
49 | "'FIRST_NAME' TEXT," + // 1: first_name
50 | "'_id' INTEGER PRIMARY KEY AUTOINCREMENT );"); // 2: id
51 | }
52 |
53 | /** Drops the underlying database table. */
54 | public static void dropTable(SQLiteDatabase db, boolean ifExists) {
55 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "'USER'";
56 | db.execSQL(sql);
57 | }
58 |
59 | /** @inheritdoc */
60 | @Override
61 | protected void bindValues(SQLiteStatement stmt, User entity) {
62 | stmt.clearBindings();
63 |
64 | String last_name = entity.getLast_name();
65 | if (last_name != null) {
66 | stmt.bindString(1, last_name);
67 | }
68 |
69 | String first_name = entity.getFirst_name();
70 | if (first_name != null) {
71 | stmt.bindString(2, first_name);
72 | }
73 |
74 | Long id = entity.getId();
75 | if (id != null) {
76 | stmt.bindLong(3, id);
77 | }
78 | }
79 |
80 | /** @inheritdoc */
81 | @Override
82 | public Long readKey(Cursor cursor, int offset) {
83 | return cursor.isNull(offset + 2) ? null : cursor.getLong(offset + 2);
84 | }
85 |
86 | /** @inheritdoc */
87 | @Override
88 | public User readEntity(Cursor cursor, int offset) {
89 | User entity = new User( //
90 | cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0), // last_name
91 | cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // first_name
92 | cursor.isNull(offset + 2) ? null : cursor.getLong(offset + 2) // id
93 | );
94 | return entity;
95 | }
96 |
97 | /** @inheritdoc */
98 | @Override
99 | public void readEntity(Cursor cursor, User entity, int offset) {
100 | entity.setLast_name(cursor.isNull(offset + 0) ? null : cursor.getString(offset + 0));
101 | entity.setFirst_name(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1));
102 | entity.setId(cursor.isNull(offset + 2) ? null : cursor.getLong(offset + 2));
103 | }
104 |
105 | /** @inheritdoc */
106 | @Override
107 | protected Long updateKeyAfterInsert(User entity, long rowId) {
108 | entity.setId(rowId);
109 | return rowId;
110 | }
111 |
112 | /** @inheritdoc */
113 | @Override
114 | public Long getKey(User entity) {
115 | if(entity != null) {
116 | return entity.getId();
117 | } else {
118 | return null;
119 | }
120 | }
121 |
122 | /** @inheritdoc */
123 | @Override
124 | protected boolean isEntityUpdateable() {
125 | return true;
126 | }
127 |
128 | /** Internal query to resolve the "readers" to-many relationship of Message. */
129 | public List _queryMessage_Readers(Long id) {
130 | synchronized (this) {
131 | if (message_ReadersQuery == null) {
132 | QueryBuilder queryBuilder = queryBuilder();
133 | queryBuilder.where(Properties.Id.eq(null));
134 | message_ReadersQuery = queryBuilder.build();
135 | }
136 | }
137 | Query query = message_ReadersQuery.forCurrentThread();
138 | query.setParameter(0, id);
139 | return query.list();
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/ormlite/Contact.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.ormlite;
2 |
3 | import android.provider.BaseColumns;
4 |
5 | import com.j256.ormlite.field.DataType;
6 | import com.j256.ormlite.field.DatabaseField;
7 |
8 | public class Contact {
9 |
10 | public static final String LAST_NAME_COLUMN = "last_name";
11 |
12 | public static final String FIRST_NAME_COLUMN = "first_name";
13 |
14 | @DatabaseField(columnName = BaseColumns._ID, generatedId = true, dataType = DataType.LONG)
15 | private long mId;
16 |
17 | @DatabaseField(columnName = LAST_NAME_COLUMN, dataType = DataType.STRING)
18 | private String mLastName;
19 |
20 | @DatabaseField(columnName = FIRST_NAME_COLUMN, dataType = DataType.STRING)
21 | private String mFirstName;
22 |
23 | public long getId() {
24 | return mId;
25 | }
26 |
27 | public void setId(long id) {
28 | this.mId = id;
29 | }
30 |
31 | public String getLastName() {
32 | return mLastName;
33 | }
34 |
35 | public void setLastName(String lastName) {
36 | this.mLastName = lastName;
37 | }
38 |
39 | public String getFirstName() {
40 | return mFirstName;
41 | }
42 |
43 | public void setFirstName(String firstName) {
44 | this.mFirstName = firstName;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/ormlite/DataBaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.ormlite;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 |
6 | import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
7 | import com.j256.ormlite.support.ConnectionSource;
8 | import com.littleinc.orm_benchmark.R;
9 |
10 | public class DataBaseHelper extends OrmLiteSqliteOpenHelper {
11 |
12 | // DB CONFIG
13 | private static int DB_VERSION = 1;
14 |
15 | private static String DB_NAME = "ormlite_db";
16 |
17 | private static DataBaseHelper sInstance;
18 |
19 | public static void init(Context context, boolean isInMemory) {
20 | sInstance = new DataBaseHelper(context, isInMemory);
21 | }
22 |
23 | public static DataBaseHelper getInstance() {
24 | if (sInstance == null) {
25 | throw new InstantiationError();
26 | }
27 | return sInstance;
28 | }
29 |
30 | private DataBaseHelper(Context context, boolean isInMemory) {
31 | super(context, (isInMemory ? null : DB_NAME), null, DB_VERSION,
32 | R.raw.ormlite_config);
33 | }
34 |
35 | @Override
36 | public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
37 | }
38 |
39 | @Override
40 | public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource,
41 | int oldVersion, int newVersion) {
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/ormlite/Message.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.ormlite;
2 |
3 | import java.sql.SQLException;
4 |
5 | import android.provider.BaseColumns;
6 |
7 | import com.j256.ormlite.dao.Dao;
8 | import com.j256.ormlite.dao.ForeignCollection;
9 | import com.j256.ormlite.field.DataType;
10 | import com.j256.ormlite.field.DatabaseField;
11 | import com.j256.ormlite.field.ForeignCollectionField;
12 | import com.j256.ormlite.table.DatabaseTable;
13 |
14 | @DatabaseTable(tableName = Message.TABLE_NAME)
15 | public class Message {
16 |
17 | public static final String TABLE_NAME = "message";
18 |
19 | public static final String CONTENT = "content";
20 |
21 | public static final String READERS = "readers";
22 |
23 | public static final String SORTED_BY = "sorted_by";
24 |
25 | public static final String CLIENT_ID = "client_id";
26 |
27 | public static final String SENDER_ID = "sender_id";
28 |
29 | public static final String CHANNEL_ID = "channel_id";
30 |
31 | public static final String COMMAND_ID = "command_id";
32 |
33 | public static final String CREATED_AT = "created_at";
34 |
35 | @DatabaseField(columnName = BaseColumns._ID, generatedId = true, dataType = DataType.LONG)
36 | private long mId;
37 |
38 | @DatabaseField(columnName = CLIENT_ID, dataType = DataType.LONG)
39 | private long mClientId;
40 |
41 | @DatabaseField(columnName = COMMAND_ID, index = true, dataType = DataType.LONG)
42 | private long mCommandId;
43 |
44 | @DatabaseField(columnName = SORTED_BY, dataType = DataType.DOUBLE)
45 | private double mSortedBy;
46 |
47 | @DatabaseField(columnName = CREATED_AT, dataType = DataType.INTEGER)
48 | private int mCreatedAt;
49 |
50 | @DatabaseField(columnName = CONTENT, dataType = DataType.STRING)
51 | private String mContent;
52 |
53 | @DatabaseField(columnName = SENDER_ID, canBeNull = false, dataType = DataType.LONG)
54 | private long mSenderId;
55 |
56 | @DatabaseField(columnName = CHANNEL_ID, canBeNull = false, dataType = DataType.LONG)
57 | private long mChannelId;
58 |
59 | @ForeignCollectionField(eager = false, columnName = READERS)
60 | private ForeignCollection mReaders;
61 |
62 | private static Dao sDao;
63 |
64 | public static Dao getDao() {
65 | if (sDao == null) {
66 | try {
67 | sDao = DataBaseHelper.getInstance().getDao(Message.class);
68 | } catch (SQLException e) {
69 | e.printStackTrace();
70 | }
71 | }
72 | return sDao;
73 | }
74 |
75 | public long getId() {
76 | return mId;
77 | }
78 |
79 | public void setId(long id) {
80 | this.mId = id;
81 | }
82 |
83 | public long getClientId() {
84 | return mClientId;
85 | }
86 |
87 | public void setClientId(long clientId) {
88 | this.mClientId = clientId;
89 | }
90 |
91 | public long getCommandId() {
92 | return mCommandId;
93 | }
94 |
95 | public void setCommandId(long commandId) {
96 | this.mCommandId = commandId;
97 | }
98 |
99 | public double getSortedBy() {
100 | return mSortedBy;
101 | }
102 |
103 | public void setSortedBy(double sortedBy) {
104 | this.mSortedBy = sortedBy;
105 | }
106 |
107 | public int getCreatedAt() {
108 | return mCreatedAt;
109 | }
110 |
111 | public void setCreatedAt(int createdAt) {
112 | this.mCreatedAt = createdAt;
113 | }
114 |
115 | public String getContent() {
116 | return mContent;
117 | }
118 |
119 | public void setContent(String content) {
120 | this.mContent = content;
121 | }
122 |
123 | public long getSenderId() {
124 | return mSenderId;
125 | }
126 |
127 | public void setSenderId(long senderId) {
128 | this.mSenderId = senderId;
129 | }
130 |
131 | public long getChannelId() {
132 | return mChannelId;
133 | }
134 |
135 | public void setChannelId(long channelId) {
136 | this.mChannelId = channelId;
137 | }
138 |
139 | public ForeignCollection getReaders() {
140 | return mReaders;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/ormlite/ORMLiteExecutor.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.ormlite;
2 |
3 | import static com.littleinc.orm_benchmark.util.Util.getRandomString;
4 |
5 | import java.sql.SQLException;
6 | import java.util.LinkedList;
7 | import java.util.List;
8 |
9 | import android.content.Context;
10 | import android.database.sqlite.SQLiteDatabase;
11 | import android.util.Log;
12 |
13 | import com.j256.ormlite.stmt.SelectArg;
14 | import com.j256.ormlite.support.ConnectionSource;
15 | import com.j256.ormlite.table.TableUtils;
16 | import com.littleinc.orm_benchmark.BenchmarkExecutable;
17 | import com.littleinc.orm_benchmark.util.Util;
18 |
19 | public class ORMLiteExecutor implements BenchmarkExecutable {
20 |
21 | private static final String TAG = "ORMLiteExecutor";
22 |
23 | private DataBaseHelper mHelper;
24 |
25 | @Override
26 | public void init(Context context, boolean useInMemoryDb) {
27 | Log.d(TAG, "Creating DataBaseHelper");
28 | DataBaseHelper.init(context, useInMemoryDb);
29 | mHelper = DataBaseHelper.getInstance();
30 | }
31 |
32 | @Override
33 | public long createDbStructure() throws SQLException {
34 | long start = System.nanoTime();
35 | ConnectionSource connectionSource = mHelper.getConnectionSource();
36 | TableUtils.createTable(connectionSource, User.class);
37 | TableUtils.createTable(connectionSource, Message.class);
38 | return System.nanoTime() - start;
39 | }
40 |
41 | @Override
42 | public long writeWholeData() throws SQLException {
43 | List users = new LinkedList();
44 | for (int i = 0; i < NUM_USER_INSERTS; i++) {
45 | User newUser = new User();
46 | newUser.setLastName(getRandomString(10));
47 | newUser.setFirstName(getRandomString(10));
48 |
49 | users.add(newUser);
50 | }
51 |
52 | List messages = new LinkedList();
53 | for (int i = 0; i < NUM_MESSAGE_INSERTS; i++) {
54 | Message newMessage = new Message();
55 | newMessage.setCommandId(i);
56 | newMessage.setSortedBy(System.nanoTime());
57 | newMessage.setContent(Util.getRandomString(100));
58 | newMessage.setClientId(System.currentTimeMillis());
59 | newMessage
60 | .setSenderId(Math.round(Math.random() * NUM_USER_INSERTS));
61 | newMessage
62 | .setChannelId(Math.round(Math.random() * NUM_USER_INSERTS));
63 | newMessage.setCreatedAt((int) (System.currentTimeMillis() / 1000L));
64 |
65 | messages.add(newMessage);
66 | }
67 |
68 | long start = System.nanoTime();
69 | SQLiteDatabase db = mHelper.getReadableDatabase();
70 | db.beginTransaction();
71 |
72 | try {
73 | for (User user : users) {
74 | User.getDao().createOrUpdate(user);
75 | }
76 | Log.d(TAG, "Done, wrote " + NUM_USER_INSERTS + " users");
77 |
78 | for (Message message : messages) {
79 | Message.getDao().createOrUpdate(message);
80 | }
81 | Log.d(TAG, "Done, wrote " + NUM_MESSAGE_INSERTS + " messages");
82 |
83 | db.setTransactionSuccessful();
84 | } finally {
85 | db.endTransaction();
86 | }
87 | return System.nanoTime() - start;
88 | }
89 |
90 | @Override
91 | public long readWholeData() throws SQLException {
92 | long start = System.nanoTime();
93 | Log.d(TAG,
94 | "Read, " + mHelper.getDao(Message.class).queryForAll().size()
95 | + " rows");
96 | return System.nanoTime() - start;
97 | }
98 |
99 | @Override
100 | public long readIndexedField() throws SQLException {
101 | long start = System.nanoTime();
102 | Log.d(TAG,
103 | "Read, "
104 | + mHelper
105 | .getDao(Message.class)
106 | .queryForEq(Message.COMMAND_ID,
107 | LOOK_BY_INDEXED_FIELD).size() + " rows");
108 | return System.nanoTime() - start;
109 | }
110 |
111 | @Override
112 | public long readSearch() throws SQLException {
113 | SelectArg arg = new SelectArg("%" + SEARCH_TERM + "%");
114 | long start = System.nanoTime();
115 | Log.d(TAG,
116 | "Read, "
117 | + mHelper.getDao(Message.class).queryBuilder()
118 | .limit(SEARCH_LIMIT).where()
119 | .like(Message.CONTENT, arg).query().size()
120 | + " rows");
121 | return System.nanoTime() - start;
122 | }
123 |
124 | @Override
125 | public long dropDb() throws SQLException {
126 | long start = System.nanoTime();
127 | ConnectionSource connectionSource = mHelper.getConnectionSource();
128 | TableUtils.dropTable(connectionSource, User.class, true);
129 | TableUtils.dropTable(connectionSource, Message.class, true);
130 | return System.nanoTime() - start;
131 | }
132 |
133 | @Override
134 | public String getOrmName() {
135 | return "ORMLite";
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/ormlite/User.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.ormlite;
2 |
3 | import java.sql.SQLException;
4 |
5 | import com.j256.ormlite.dao.Dao;
6 | import com.j256.ormlite.field.DatabaseField;
7 | import com.j256.ormlite.table.DatabaseTable;
8 |
9 | @DatabaseTable(tableName = User.TABLE_NAME)
10 | public class User extends Contact {
11 |
12 | public static final String TABLE_NAME = "user";
13 |
14 | private static Dao sDao;
15 |
16 | @DatabaseField(columnName = "message_id", foreign = true, foreignAutoRefresh = false)
17 | private Message mMessage;
18 |
19 | public User() {
20 | }
21 |
22 | public static Dao getDao() {
23 | if (sDao == null) {
24 | try {
25 | sDao = DataBaseHelper.getInstance().getDao(User.class);
26 | } catch (SQLException e) {
27 | e.printStackTrace();
28 | }
29 | }
30 | return sDao;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/ormlite/config/DBConfigUtil.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.ormlite.config;
2 |
3 | import com.j256.ormlite.android.apptools.OrmLiteConfigUtil;
4 | import com.littleinc.orm_benchmark.ormlite.Message;
5 | import com.littleinc.orm_benchmark.ormlite.User;
6 |
7 | public class DBConfigUtil extends OrmLiteConfigUtil {
8 |
9 | private static final Class>[] sClasses = new Class[] { User.class, Message.class };
10 |
11 | /**
12 | * To make this work in Android Studio, you may need to update your
13 | * Run Configuration as explained here:
14 | * http://stackoverflow.com/a/17332546
15 | *
16 | * You must run this method to regenerate res/raw/ormlite_config.txt
17 | * any time the database definitions are updated.
18 | *
19 | * You need to update the Run Configuration for this class to set a
20 | * JRE, and remove the Android bootstrap entry. Instructions here:
21 | * http://ormlite.com/javadoc/ormlite-core/doc-files/ormlite_4.html
22 | *
23 | * If you are adding a new ORM managed class you must add it to the
24 | * array of classes above.
25 | */
26 | public static void main(String[] args) throws Exception {
27 | writeConfigFile("ormlite_config.txt", sClasses);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqlite/DataBaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqlite;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | public class DataBaseHelper extends SQLiteOpenHelper {
8 |
9 | // DB CONFIG
10 | private static int DB_VERSION = 1;
11 |
12 | private static String DB_NAME = "sqlite_db";
13 |
14 | public DataBaseHelper(Context context, boolean isInMemory) {
15 | super(context, (isInMemory ? null : DB_NAME), null, DB_VERSION);
16 | }
17 |
18 | @Override
19 | public void onCreate(SQLiteDatabase db) {
20 | }
21 |
22 | @Override
23 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqlite/Message.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqlite;
2 |
3 | import java.util.List;
4 |
5 | import android.content.ContentValues;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.database.sqlite.SQLiteOpenHelper;
8 | import android.provider.BaseColumns;
9 |
10 | import com.littleinc.orm_benchmark.util.Util;
11 |
12 | public class Message {
13 |
14 | public static final String TABLE_NAME = "message";
15 |
16 | public static final String CONTENT = "content";
17 |
18 | public static final String READERS = "readers";
19 |
20 | public static final String SORTED_BY = "sorted_by";
21 |
22 | public static final String CLIENT_ID = "client_id";
23 |
24 | public static final String SENDER_ID = "sender_id";
25 |
26 | public static final String CHANNEL_ID = "channel_id";
27 |
28 | public static final String COMMAND_ID = "command_id";
29 |
30 | public static final String CREATED_AT = "created_at";
31 |
32 | protected long mId;
33 |
34 | protected long mClientId;
35 |
36 | protected long mCommandId;
37 |
38 | protected double mSortedBy;
39 |
40 | protected int mCreatedAt;
41 |
42 | protected String mContent;
43 |
44 | protected long mSenderId;
45 |
46 | protected long mChannelId;
47 |
48 | protected List mReaders;
49 |
50 | public static final String[] PROJECTION = new String[] { CONTENT,
51 | SORTED_BY, CLIENT_ID, SENDER_ID, CHANNEL_ID, COMMAND_ID, CREATED_AT };
52 |
53 | public static void createTable(SQLiteOpenHelper helper) {
54 | SQLiteDatabase db = helper.getWritableDatabase();
55 |
56 | db.execSQL(new StringBuilder("CREATE TABLE '").append(TABLE_NAME)
57 | .append("' ('").append(BaseColumns._ID)
58 | .append("' INTEGER PRIMARY KEY AUTOINCREMENT, '")
59 | .append(CLIENT_ID).append("' INTEGER, '").append(SORTED_BY)
60 | .append("' REAL, '").append(CREATED_AT).append("' INTEGER, '")
61 | .append(CONTENT).append("' TEXT, '").append(SENDER_ID)
62 | .append("' INTEGER NOT NULL, '").append(CHANNEL_ID)
63 | .append("' INTEGER NOT NULL, '").append(COMMAND_ID)
64 | .append("' INTEGER);").toString());
65 |
66 | db.execSQL(new StringBuilder("CREATE INDEX IDX_MESSAGE_COMMAND_ID ON ")
67 | .append(TABLE_NAME).append(" (").append(COMMAND_ID)
68 | .append(");").toString());
69 | }
70 |
71 | public static void dropTable(SQLiteOpenHelper helper) {
72 | SQLiteDatabase db = helper.getWritableDatabase();
73 |
74 | db.execSQL(new StringBuilder("DROP TABLE '").append(TABLE_NAME)
75 | .append("';").toString());
76 | }
77 |
78 | public long getId() {
79 | return mId;
80 | }
81 |
82 | public void setId(long id) {
83 | this.mId = id;
84 | }
85 |
86 | public long getClientId() {
87 | return mClientId;
88 | }
89 |
90 | public void setClientId(long clientId) {
91 | this.mClientId = clientId;
92 | }
93 |
94 | public long getCommandId() {
95 | return mCommandId;
96 | }
97 |
98 | public void setCommandId(long commandId) {
99 | this.mCommandId = commandId;
100 | }
101 |
102 | public double getSortedBy() {
103 | return mSortedBy;
104 | }
105 |
106 | public void setSortedBy(double sortedBy) {
107 | this.mSortedBy = sortedBy;
108 | }
109 |
110 | public int getCreatedAt() {
111 | return mCreatedAt;
112 | }
113 |
114 | public void setCreatedAt(int createdAt) {
115 | this.mCreatedAt = createdAt;
116 | }
117 |
118 | public String getContent() {
119 | return mContent;
120 | }
121 |
122 | public void setContent(String content) {
123 | this.mContent = content;
124 | }
125 |
126 | public long getSenderId() {
127 | return mSenderId;
128 | }
129 |
130 | public void setSenderId(long senderId) {
131 | this.mSenderId = senderId;
132 | }
133 |
134 | public long getChannelId() {
135 | return mChannelId;
136 | }
137 |
138 | public void setChannelId(long channelId) {
139 | this.mChannelId = channelId;
140 | }
141 |
142 | public void setReaders(List readers) {
143 | mReaders = readers;
144 | }
145 |
146 | public List getReaders() {
147 | return mReaders;
148 | }
149 |
150 | public boolean hasReaders() {
151 | return mReaders != null && !mReaders.isEmpty();
152 | }
153 |
154 | public void fillMessageWithRandomData(int messageNumber, int totalNumber) {
155 | setCommandId(messageNumber);
156 | setSortedBy(System.nanoTime());
157 | setContent(Util.getRandomString(100));
158 | setClientId(System.currentTimeMillis());
159 | setSenderId(Math.round(Math.random() * totalNumber));
160 | setChannelId(Math.round(Math.random() * totalNumber));
161 | setCreatedAt((int) (System.currentTimeMillis() / 1000L));
162 | }
163 |
164 | public ContentValues prepareForInsert() {
165 | ContentValues contentValues = new ContentValues();
166 | contentValues.put(CONTENT, mContent);
167 | contentValues.put(SORTED_BY, mSortedBy);
168 | contentValues.put(CLIENT_ID, mClientId);
169 | contentValues.put(SENDER_ID, mSenderId);
170 | contentValues.put(CHANNEL_ID, mChannelId);
171 | contentValues.put(COMMAND_ID, mCommandId);
172 | contentValues.put(CREATED_AT, mCreatedAt);
173 | return contentValues;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqlite/SQLiteExecutor.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqlite;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.util.Log;
7 |
8 | import com.littleinc.orm_benchmark.BenchmarkExecutable;
9 |
10 | import java.sql.SQLException;
11 | import java.util.LinkedList;
12 | import java.util.List;
13 |
14 | /**
15 | * An unoptimized set of SQLite operations for reading and writing the test database objects.
16 | *
17 | * See {@link com.littleinc.orm_benchmark.sqliteoptimized.OptimizedSQLiteExecutor} for optimized
18 | * versions of these SQLite operations.
19 | */
20 | public class SQLiteExecutor implements BenchmarkExecutable {
21 |
22 | private static final String TAG = "SQLiteExecutor";
23 |
24 | private DataBaseHelper mHelper;
25 |
26 | @Override
27 | public String getOrmName() {
28 | return "RAW";
29 | }
30 |
31 | @Override
32 | public void init(Context context, boolean useInMemoryDb) {
33 | Log.d(TAG, "Creating DataBaseHelper");
34 | mHelper = new DataBaseHelper(context, useInMemoryDb);
35 | }
36 |
37 | @Override
38 | public long createDbStructure() throws SQLException {
39 | long start = System.nanoTime();
40 | User.createTable(mHelper);
41 | Message.createTable(mHelper);
42 | return System.nanoTime() - start;
43 | }
44 |
45 | @Override
46 | public long writeWholeData() throws SQLException {
47 | List users = new LinkedList<>();
48 | for (int i = 0; i < NUM_USER_INSERTS; i++) {
49 | User newUser = new User();
50 | newUser.fillUserWithRandomData();
51 | users.add(newUser);
52 | }
53 |
54 | List messages = new LinkedList<>();
55 | for (int i = 0; i < NUM_MESSAGE_INSERTS; i++) {
56 | Message newMessage = new Message();
57 | newMessage.fillMessageWithRandomData(i, NUM_USER_INSERTS);
58 | messages.add(newMessage);
59 | }
60 |
61 | long start = System.nanoTime();
62 | SQLiteDatabase db = mHelper.getWritableDatabase();
63 |
64 | try {
65 | db.beginTransaction();
66 |
67 | for (User user : users) {
68 | db.insert(User.TABLE_NAME, null, user.prepareForInsert());
69 | }
70 | Log.d(TAG, "Done, wrote " + NUM_USER_INSERTS + " users");
71 |
72 | for (Message message : messages) {
73 | db.insert(Message.TABLE_NAME, null, message.prepareForInsert());
74 | }
75 | Log.d(TAG, "Done, wrote " + NUM_MESSAGE_INSERTS + " messages");
76 | db.setTransactionSuccessful();
77 | } finally {
78 | db.endTransaction();
79 | }
80 | return System.nanoTime() - start;
81 | }
82 |
83 | @Override
84 | public long readWholeData() throws SQLException {
85 | long start = System.nanoTime();
86 | Cursor c = null;
87 | try {
88 | SQLiteDatabase db = mHelper.getReadableDatabase();
89 | List messages = new LinkedList();
90 | c = db.query(Message.TABLE_NAME, Message.PROJECTION, null, null,
91 | null, null, null);
92 |
93 | while (c != null && c.moveToNext()) {
94 | Message newMessage = new Message();
95 | newMessage.setChannelId(c.getLong(c
96 | .getColumnIndex(Message.CHANNEL_ID)));
97 | newMessage.setClientId(c.getLong(c
98 | .getColumnIndex(Message.CLIENT_ID)));
99 | newMessage.setCommandId(c.getLong(c
100 | .getColumnIndex(Message.COMMAND_ID)));
101 | newMessage.setContent(c.getString(c
102 | .getColumnIndex(Message.CONTENT)));
103 | newMessage.setCreatedAt(c.getInt(c
104 | .getColumnIndex(Message.CREATED_AT)));
105 | newMessage.setSenderId(c.getLong(c
106 | .getColumnIndex(Message.SENDER_ID)));
107 | newMessage.setSortedBy(c.getDouble(c
108 | .getColumnIndex(Message.SORTED_BY)));
109 |
110 | messages.add(newMessage);
111 | }
112 | Log.d(TAG,
113 | "Read, " + messages.size() + " rows");
114 | } finally {
115 | if (c != null) {
116 | c.close();
117 | }
118 | }
119 | return System.nanoTime() - start;
120 | }
121 |
122 | @Override
123 | public long readIndexedField() throws SQLException {
124 | long start = System.nanoTime();
125 | Cursor c = null;
126 | try {
127 | SQLiteDatabase db = mHelper.getReadableDatabase();
128 | String selection = Message.COMMAND_ID + "=?";
129 | String[] selectionArgs = new String[] { String
130 | .valueOf(LOOK_BY_INDEXED_FIELD) };
131 | c = db.query(Message.TABLE_NAME, Message.PROJECTION, selection,
132 | selectionArgs, null, null, null);
133 |
134 | if (c != null && c.moveToFirst()) {
135 | Message newMessage = new Message();
136 | newMessage.setChannelId(c.getLong(c
137 | .getColumnIndex(Message.CHANNEL_ID)));
138 | newMessage.setClientId(c.getLong(c
139 | .getColumnIndex(Message.CLIENT_ID)));
140 | newMessage.setCommandId(c.getLong(c
141 | .getColumnIndex(Message.COMMAND_ID)));
142 | newMessage.setContent(c.getString(c
143 | .getColumnIndex(Message.CONTENT)));
144 | newMessage.setCreatedAt(c.getInt(c
145 | .getColumnIndex(Message.CREATED_AT)));
146 | newMessage.setSenderId(c.getLong(c
147 | .getColumnIndex(Message.SENDER_ID)));
148 | newMessage.setSortedBy(c.getDouble(c
149 | .getColumnIndex(Message.SORTED_BY)));
150 |
151 | Log.d(TAG,
152 | "Read, " + c.getCount() + " rows");
153 | }
154 | } finally {
155 | if (c != null) {
156 | c.close();
157 | }
158 | }
159 | return System.nanoTime() - start;
160 | }
161 |
162 | @Override
163 | public long readSearch() throws SQLException {
164 | long start = System.nanoTime();
165 | Cursor c = null;
166 | try {
167 | SQLiteDatabase db = mHelper.getReadableDatabase();
168 | String selection = Message.CONTENT + " LIKE ?";
169 | List messages = new LinkedList();
170 | String[] selectionArgs = new String[] { '%' + SEARCH_TERM + '%' };
171 | c = db.query(Message.TABLE_NAME, Message.PROJECTION, selection,
172 | selectionArgs, null, null, null,
173 | String.valueOf(SEARCH_LIMIT));
174 |
175 | while (c != null && c.moveToNext()) {
176 | Message newMessage = new Message();
177 | newMessage.setChannelId(c.getLong(c
178 | .getColumnIndex(Message.CHANNEL_ID)));
179 | newMessage.setClientId(c.getLong(c
180 | .getColumnIndex(Message.CLIENT_ID)));
181 | newMessage.setCommandId(c.getLong(c
182 | .getColumnIndex(Message.COMMAND_ID)));
183 | newMessage.setContent(c.getString(c
184 | .getColumnIndex(Message.CONTENT)));
185 | newMessage.setCreatedAt(c.getInt(c
186 | .getColumnIndex(Message.CREATED_AT)));
187 | newMessage.setSenderId(c.getLong(c
188 | .getColumnIndex(Message.SENDER_ID)));
189 | newMessage.setSortedBy(c.getDouble(c
190 | .getColumnIndex(Message.SORTED_BY)));
191 |
192 | messages.add(newMessage);
193 | }
194 | Log.d(TAG,
195 | "Read, " + messages.size() + " rows");
196 | } finally {
197 | if (c != null) {
198 | c.close();
199 | }
200 | }
201 | return System.nanoTime() - start;
202 | }
203 |
204 | @Override
205 | public long dropDb() throws SQLException {
206 | long start = System.nanoTime();
207 | User.dropTable(mHelper);
208 | Message.dropTable(mHelper);
209 | return System.nanoTime() - start;
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqlite/User.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqlite;
2 |
3 | import android.content.ContentValues;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 | import android.provider.BaseColumns;
7 |
8 | import static com.littleinc.orm_benchmark.util.Util.getRandomString;
9 |
10 | public class User {
11 |
12 | public static final String TABLE_NAME = "user";
13 |
14 | public static final String LAST_NAME_COLUMN = "last_name";
15 |
16 | public static final String FIRST_NAME_COLUMN = "first_name";
17 |
18 | protected long mId;
19 |
20 | protected String mLastName;
21 |
22 | protected String mFirstName;
23 |
24 | public static void createTable(SQLiteOpenHelper helper) {
25 | helper.getWritableDatabase().execSQL(
26 | new StringBuilder("CREATE TABLE '").append(TABLE_NAME)
27 | .append("' ('").append(BaseColumns._ID)
28 | .append("' INTEGER PRIMARY KEY AUTOINCREMENT, '")
29 | .append(LAST_NAME_COLUMN).append("' TEXT, '")
30 | .append(FIRST_NAME_COLUMN).append("' TEXT);")
31 | .toString());
32 | }
33 |
34 | public static void dropTable(SQLiteOpenHelper helper) {
35 | SQLiteDatabase db = helper.getWritableDatabase();
36 |
37 | db.execSQL(new StringBuilder("DROP TABLE '").append(TABLE_NAME)
38 | .append("';").toString());
39 | }
40 |
41 | public long getId() {
42 | return mId;
43 | }
44 |
45 | public void setId(long id) {
46 | this.mId = id;
47 | }
48 |
49 | public String getLastName() {
50 | return mLastName;
51 | }
52 |
53 | public void setLastName(String lastName) {
54 | this.mLastName = lastName;
55 | }
56 |
57 | public String getFirstName() {
58 | return mFirstName;
59 | }
60 |
61 | public void setFirstName(String firstName) {
62 | this.mFirstName = firstName;
63 | }
64 |
65 | public void fillUserWithRandomData() {
66 | setLastName(getRandomString(10));
67 | setFirstName(getRandomString(10));
68 | }
69 |
70 | public ContentValues prepareForInsert() {
71 | ContentValues contentValues = new ContentValues();
72 | contentValues.put(LAST_NAME_COLUMN, mLastName);
73 | contentValues.put(FIRST_NAME_COLUMN, mFirstName);
74 | return contentValues;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqliteoptimized/DataBaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqliteoptimized;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | public class DataBaseHelper extends SQLiteOpenHelper {
8 |
9 | // DB CONFIG
10 | private static int DB_VERSION = 1;
11 |
12 | private static String DB_NAME = "sqliteopt_db";
13 |
14 | public DataBaseHelper(Context context, boolean isInMemory) {
15 | super(context, (isInMemory ? null : DB_NAME), null, DB_VERSION);
16 | }
17 |
18 | @Override
19 | public void onCreate(SQLiteDatabase db) {
20 | }
21 |
22 | @Override
23 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqliteoptimized/OptimizedMessage.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqliteoptimized;
2 |
3 | import android.database.sqlite.SQLiteStatement;
4 |
5 | import com.littleinc.orm_benchmark.sqlite.Message;
6 |
7 | public class OptimizedMessage extends Message {
8 |
9 | public void prepareForInsert(final SQLiteStatement insertMessage) {
10 | insertMessage.bindString(1, mContent);
11 | insertMessage.bindDouble(2, mSortedBy);
12 | insertMessage.bindLong(3, mClientId);
13 | insertMessage.bindLong(4, mSenderId);
14 | insertMessage.bindLong(5, mChannelId);
15 | insertMessage.bindLong(6, mCommandId);
16 | insertMessage.bindLong(7, mCreatedAt);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqliteoptimized/OptimizedSQLiteExecutor.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqliteoptimized;
2 |
3 | import android.content.Context;
4 | import android.database.Cursor;
5 | import android.database.sqlite.SQLiteDatabase;
6 | import android.database.sqlite.SQLiteStatement;
7 | import android.util.Log;
8 |
9 | import com.littleinc.orm_benchmark.BenchmarkExecutable;
10 | import com.littleinc.orm_benchmark.sqlite.Message;
11 | import com.littleinc.orm_benchmark.sqlite.User;
12 | import com.littleinc.orm_benchmark.util.Util;
13 |
14 | import java.sql.SQLException;
15 | import java.util.LinkedList;
16 | import java.util.List;
17 |
18 | import static com.littleinc.orm_benchmark.util.Util.getRandomString;
19 |
20 | /**
21 | * This executor takes the basic idea of the standard Android sqlLite query helper, but adds a few optimizations.
22 | *
23 | * Select optimization
24 | * A Cursor can only access columns by their respective position in the result
25 | * the standard way of reading the fields value is cursor.getString(cursor.getColumnIndex("field_name"))
26 | * this actually loops through all column names until it finds one that matches and then return that index.
27 | *
28 | * To decrease unnecessary lookup, we do this once before we read any of the rows, and remembers the position
29 | * in local variables.
30 | *
31 | * Insert optimizations
32 | * The database.Insert function does not cache the insert query. Instead it re-creates the full statement
33 | * for each time its called including adding all values to the statement
34 | * What we do here instead is to create the SQL-statement manually and let the database driver compile it
35 | * for us. This creates a re-usable and very fast executable statement for us.
36 | *
37 | * For each row we just need to insert the values into the statement via the bind function and then
38 | * execute it.
39 | *
40 | * Everything should of course still be encapsulated by a transaction, otherwise you will get a huge overhead
41 | * per row.
42 | *
43 | */
44 | public class OptimizedSQLiteExecutor implements BenchmarkExecutable {
45 |
46 | private static final String TAG = "OptimizedSQLiteExecutor";
47 |
48 | private DataBaseHelper mHelper;
49 |
50 | @Override
51 | public String getOrmName() {
52 | return "RAW_OPTIMIZED";
53 | }
54 |
55 | @Override
56 | public void init(Context context, boolean useInMemoryDb) {
57 | Log.d(TAG, "Creating DataBaseHelper");
58 | mHelper = new DataBaseHelper(context, useInMemoryDb);
59 | }
60 |
61 | @Override
62 | public long createDbStructure() throws SQLException {
63 | long start = System.nanoTime();
64 | User.createTable(mHelper);
65 | Message.createTable(mHelper);
66 | return System.nanoTime() - start;
67 | }
68 |
69 | @Override
70 | public long writeWholeData() throws SQLException {
71 | List users = new LinkedList<>();
72 | for (int i = 0; i < NUM_USER_INSERTS; i++) {
73 | OptimizedUser newUser = new OptimizedUser();
74 | newUser.fillUserWithRandomData();
75 | users.add(newUser);
76 | }
77 |
78 | List messages = new LinkedList<>();
79 | for (int i = 0; i < NUM_MESSAGE_INSERTS; i++) {
80 | OptimizedMessage newMessage = new OptimizedMessage();
81 | newMessage.fillMessageWithRandomData(i, NUM_USER_INSERTS);
82 | messages.add(newMessage);
83 | }
84 |
85 | long start = System.nanoTime();
86 | SQLiteDatabase db = mHelper.getWritableDatabase();
87 |
88 | SQLiteStatement insertUser = db.compileStatement(
89 | String.format("Insert into %s (%s, %s) values (?,?)",
90 | OptimizedUser.TABLE_NAME,
91 | OptimizedUser.FIRST_NAME_COLUMN,
92 | OptimizedUser.LAST_NAME_COLUMN));
93 |
94 | SQLiteStatement insertMessage = db.compileStatement(
95 | String.format("Insert into %s (%s, %s, %s, %s, %s, %s, %s) values (?,?,?,?,?,?,?)",
96 | OptimizedMessage.TABLE_NAME,
97 | OptimizedMessage.CONTENT,
98 | OptimizedMessage.SORTED_BY,
99 | OptimizedMessage.CLIENT_ID,
100 | OptimizedMessage.SENDER_ID,
101 | OptimizedMessage.CHANNEL_ID,
102 | OptimizedMessage.COMMAND_ID,
103 | OptimizedMessage.CREATED_AT ));
104 |
105 | try {
106 | db.beginTransaction();
107 |
108 | for (OptimizedUser user : users) {
109 | user.prepareForInsert(insertUser);
110 | insertUser.execute();
111 | }
112 | Log.d(TAG, "Done, wrote " + NUM_USER_INSERTS + " users");
113 |
114 | for (OptimizedMessage message : messages) {
115 | message.prepareForInsert(insertMessage);
116 | insertMessage.execute();
117 | }
118 | Log.d(TAG, "Done, wrote " + NUM_MESSAGE_INSERTS + " messages");
119 | db.setTransactionSuccessful();
120 | } finally {
121 | db.endTransaction();
122 | }
123 | return System.nanoTime() - start;
124 | }
125 |
126 | @Override
127 | public long readWholeData() throws SQLException {
128 | long start = System.nanoTime();
129 | Cursor c = null;
130 | try {
131 | SQLiteDatabase db = mHelper.getReadableDatabase();
132 | List messages = new LinkedList();
133 | c = db.query(OptimizedMessage.TABLE_NAME, OptimizedMessage.PROJECTION, null, null,
134 | null, null, null);
135 |
136 | if(c != null) {
137 |
138 | int channelIdIndex = c.getColumnIndex(OptimizedMessage.CHANNEL_ID);
139 | int clientIdIndex = c.getColumnIndex(OptimizedMessage.CLIENT_ID);
140 | int commandIdIndex = c.getColumnIndex(OptimizedMessage.COMMAND_ID);
141 | int contentIndex = c.getColumnIndex(OptimizedMessage.CONTENT);
142 | int createdAtIndex = c.getColumnIndex(OptimizedMessage.CREATED_AT);
143 | int senderIdIndex = c.getColumnIndex(OptimizedMessage.SENDER_ID);
144 | int sortedByIndex = c.getColumnIndex(OptimizedMessage.SORTED_BY);
145 |
146 | while (c.moveToNext()) {
147 | OptimizedMessage newMessage = new OptimizedMessage();
148 | newMessage.setChannelId(c.getLong(channelIdIndex));
149 | newMessage.setClientId(c.getLong(clientIdIndex));
150 | newMessage.setCommandId(c.getLong(commandIdIndex));
151 | newMessage.setContent(c.getString(contentIndex));
152 | newMessage.setCreatedAt(c.getInt(createdAtIndex));
153 | newMessage.setSenderId(c.getLong(senderIdIndex));
154 | newMessage.setSortedBy(c.getDouble(sortedByIndex));
155 |
156 | messages.add(newMessage);
157 | }
158 | }
159 | Log.d(TAG, "Read, " + messages.size() + " rows");
160 | } finally {
161 | if (c != null) {
162 | c.close();
163 | }
164 | }
165 | return System.nanoTime() - start;
166 | }
167 |
168 | @Override
169 | public long readIndexedField() throws SQLException {
170 | long start = System.nanoTime();
171 | Cursor c = null;
172 | try {
173 | SQLiteDatabase db = mHelper.getReadableDatabase();
174 | String selection = OptimizedMessage.COMMAND_ID + "=?";
175 | String[] selectionArgs = new String[] { String
176 | .valueOf(LOOK_BY_INDEXED_FIELD) };
177 | c = db.query(OptimizedMessage.TABLE_NAME, OptimizedMessage.PROJECTION, selection,
178 | selectionArgs, null, null, null);
179 |
180 | if (c != null && c.moveToFirst()) {
181 | OptimizedMessage newMessage = new OptimizedMessage();
182 | newMessage.setChannelId(c.getLong(c
183 | .getColumnIndex(OptimizedMessage.CHANNEL_ID)));
184 | newMessage.setClientId(c.getLong(c
185 | .getColumnIndex(OptimizedMessage.CLIENT_ID)));
186 | newMessage.setCommandId(c.getLong(c
187 | .getColumnIndex(OptimizedMessage.COMMAND_ID)));
188 | newMessage.setContent(c.getString(c
189 | .getColumnIndex(OptimizedMessage.CONTENT)));
190 | newMessage.setCreatedAt(c.getInt(c
191 | .getColumnIndex(OptimizedMessage.CREATED_AT)));
192 | newMessage.setSenderId(c.getLong(c
193 | .getColumnIndex(OptimizedMessage.SENDER_ID)));
194 | newMessage.setSortedBy(c.getDouble(c
195 | .getColumnIndex(OptimizedMessage.SORTED_BY)));
196 |
197 | Log.d(TAG, "Read, " + c.getCount() + " rows");
198 | }
199 | } finally {
200 | if (c != null) {
201 | c.close();
202 | }
203 | }
204 | return System.nanoTime() - start;
205 | }
206 |
207 | @Override
208 | public long readSearch() throws SQLException {
209 | long start = System.nanoTime();
210 | Cursor c = null;
211 | try {
212 | SQLiteDatabase db = mHelper.getReadableDatabase();
213 | String selection = OptimizedMessage.CONTENT + " LIKE ?";
214 | List messages = new LinkedList();
215 | String[] selectionArgs = new String[] { '%' + SEARCH_TERM + '%' };
216 | c = db.query(OptimizedMessage.TABLE_NAME, OptimizedMessage.PROJECTION, selection,
217 | selectionArgs, null, null, null,
218 | String.valueOf(SEARCH_LIMIT));
219 |
220 | if(c != null) {
221 |
222 | int channelIdIndex = c.getColumnIndex(OptimizedMessage.CHANNEL_ID);
223 | int clientIdIndex = c.getColumnIndex(OptimizedMessage.CLIENT_ID);
224 | int commandIdIndex = c.getColumnIndex(OptimizedMessage.COMMAND_ID);
225 | int contentIndex = c.getColumnIndex(OptimizedMessage.CONTENT);
226 | int createdAtIndex = c.getColumnIndex(OptimizedMessage.CREATED_AT);
227 | int senderIdIndex = c.getColumnIndex(OptimizedMessage.SENDER_ID);
228 | int sortedByIndex = c.getColumnIndex(OptimizedMessage.SORTED_BY);
229 |
230 | while (c.moveToNext()) {
231 | OptimizedMessage newMessage = new OptimizedMessage();
232 | newMessage.setChannelId(c.getLong(channelIdIndex));
233 | newMessage.setClientId(c.getLong(clientIdIndex));
234 | newMessage.setCommandId(c.getLong(commandIdIndex));
235 | newMessage.setContent(c.getString(contentIndex));
236 | newMessage.setCreatedAt(c.getInt(createdAtIndex));
237 | newMessage.setSenderId(c.getLong(senderIdIndex));
238 | newMessage.setSortedBy(c.getDouble(sortedByIndex));
239 |
240 | messages.add(newMessage);
241 | }
242 | }
243 |
244 | Log.d(TAG, "Read, " + messages.size() + " rows");
245 | } finally {
246 | if (c != null) {
247 | c.close();
248 | }
249 | }
250 | return System.nanoTime() - start;
251 | }
252 |
253 | @Override
254 | public long dropDb() throws SQLException {
255 | long start = System.nanoTime();
256 | User.dropTable(mHelper);
257 | Message.dropTable(mHelper);
258 | return System.nanoTime() - start;
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/sqliteoptimized/OptimizedUser.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.sqliteoptimized;
2 |
3 | import android.database.sqlite.SQLiteStatement;
4 |
5 | import com.littleinc.orm_benchmark.sqlite.User;
6 |
7 | public class OptimizedUser extends User {
8 |
9 | public void prepareForInsert(final SQLiteStatement insertUser) {
10 | insertUser.bindString(1, mLastName);
11 | insertUser.bindString(2, mFirstName);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/util/Util.java:
--------------------------------------------------------------------------------
1 | package com.littleinc.orm_benchmark.util;
2 |
3 | import java.util.Random;
4 | import java.util.concurrent.TimeUnit;
5 |
6 | public class Util {
7 |
8 | private static final char[] FILENAME_CHARS = new char[62];
9 |
10 | private static final Random sRandom = new Random();
11 |
12 | static {
13 | for (int idx = 0; idx < 10; ++idx)
14 | FILENAME_CHARS[idx] = (char) ('0' + idx);
15 | for (int idx = 10; idx < 36; ++idx)
16 | FILENAME_CHARS[idx] = (char) ('a' + idx - 10);
17 | for (int idx = 36; idx < 62; ++idx)
18 | FILENAME_CHARS[idx] = (char) ('A' + idx - 36);
19 | }
20 |
21 | /**
22 | * Get a random String with the provided length, containing only characters
23 | * in {@link #FILENAME_CHARS}, e.g. "2pKfEz".
24 | */
25 | public static String getRandomString(int length) {
26 | char[] buf = new char[length];
27 |
28 | for (int idx = 0; idx < buf.length; ++idx) {
29 | buf[idx] = FILENAME_CHARS[sRandom.nextInt(FILENAME_CHARS.length)];
30 | }
31 |
32 | return new String(buf);
33 | }
34 |
35 | /**
36 | * @return millis
37 | */
38 | public static String formatElapsedTime(long nanos) {
39 | return String.valueOf(TimeUnit.NANOSECONDS.toMillis(nanos));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daj/android-orm-benchmark/2d860f2a9d769bad3d059102d37d84993780aeb6/ORM-Benchmark/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daj/android-orm-benchmark/2d860f2a9d769bad3d059102d37d84993780aeb6/ORM-Benchmark/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daj/android-orm-benchmark/2d860f2a9d769bad3d059102d37d84993780aeb6/ORM-Benchmark/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daj/android-orm-benchmark/2d860f2a9d769bad3d059102d37d84993780aeb6/ORM-Benchmark/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
17 |
18 |
24 |
25 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/raw/ormlite_config.txt:
--------------------------------------------------------------------------------
1 | #
2 | # generated on 2015/05/13 11:14:27
3 | #
4 | # --table-start--
5 | dataClass=com.littleinc.orm_benchmark.ormlite.User
6 | tableName=user
7 | # --table-fields-start--
8 | # --field-start--
9 | fieldName=mMessage
10 | columnName=message_id
11 | foreign=true
12 | # --field-end--
13 | # --field-start--
14 | fieldName=mId
15 | columnName=_id
16 | dataPersister=LONG
17 | generatedId=true
18 | # --field-end--
19 | # --field-start--
20 | fieldName=mLastName
21 | columnName=last_name
22 | dataPersister=STRING
23 | # --field-end--
24 | # --field-start--
25 | fieldName=mFirstName
26 | columnName=first_name
27 | dataPersister=STRING
28 | # --field-end--
29 | # --table-fields-end--
30 | # --table-end--
31 | #################################
32 | # --table-start--
33 | dataClass=com.littleinc.orm_benchmark.ormlite.Message
34 | tableName=message
35 | # --table-fields-start--
36 | # --field-start--
37 | fieldName=mId
38 | columnName=_id
39 | dataPersister=LONG
40 | generatedId=true
41 | # --field-end--
42 | # --field-start--
43 | fieldName=mClientId
44 | columnName=client_id
45 | dataPersister=LONG
46 | # --field-end--
47 | # --field-start--
48 | fieldName=mCommandId
49 | columnName=command_id
50 | dataPersister=LONG
51 | indexName=message_command_id_idx
52 | # --field-end--
53 | # --field-start--
54 | fieldName=mSortedBy
55 | columnName=sorted_by
56 | dataPersister=DOUBLE
57 | # --field-end--
58 | # --field-start--
59 | fieldName=mCreatedAt
60 | columnName=created_at
61 | dataPersister=INTEGER
62 | # --field-end--
63 | # --field-start--
64 | fieldName=mContent
65 | columnName=content
66 | dataPersister=STRING
67 | # --field-end--
68 | # --field-start--
69 | fieldName=mSenderId
70 | columnName=sender_id
71 | dataPersister=LONG
72 | canBeNull=false
73 | # --field-end--
74 | # --field-start--
75 | fieldName=mChannelId
76 | columnName=channel_id
77 | dataPersister=LONG
78 | canBeNull=false
79 | # --field-end--
80 | # --field-start--
81 | fieldName=mReaders
82 | columnName=readers
83 | foreignCollection=true
84 | foreignCollectionColumnName=readers
85 | # --field-end--
86 | # --table-fields-end--
87 | # --table-end--
88 | #################################
89 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ORM-Benchmark
5 | Show Results
6 | Task
7 | Results…
8 | ORMLite
9 | GreenDAO
10 | Run Benchmark
11 |
12 |
--------------------------------------------------------------------------------
/ORM-Benchmark/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #android-orm-benchmark
2 |
3 | ##Summary
4 |
5 | ORM-Benchmark is an Android application built in Eclipse that benchmarks the following against each other:
6 |
7 | - [ORMLite](http://ormlite.com/)
8 | - [GreenDAO](http://greendao-orm.com/)
9 | - [Android raw SQLite](http://developer.android.com/guide/topics/data/data-storage.html#db)
10 |
11 | The benchmark runs the following tasks:
12 |
13 | - CREATE_DB - Creation of database structure
14 | - WRITE_DATA - Writing 1000 'user' objects and 10000 'message' objects
15 | - READ_DATA - Read all 10000 'message' objects in the table
16 | - READ_INDEXED - Read an indexed field (the 5000th 'message' in the table)
17 | - READ_SEARCH - Query the first 100 rows that matches a search term (using LIKE)
18 | - DROP_DB - Drop database strucuture
19 |
20 | Each task is run 5 times, and the application reports the average time for each in milliseconds.
21 |
22 | ##Sample Output
23 |
24 | Building and running the ORM-Benchmark project produces output similar to that below.
25 |
26 | - The times are in milliseconds.
27 | - The results are shown on the device and are also logged to Logcat.
28 |
29 | The results below combine the in-memory database results with the on disk database results side by side. They are from a Nexus 4 on 20th Dec 2013, and we've put an "M" in front of the tests for the in-memory results.
30 |
31 |
32 | Task CREATE_DB
33 | M RAW - Avg: 4
34 | RAW - Avg: 230
35 |
36 | M ORMLite - Avg: 6
37 | ORMLite - Avg: 233
38 |
39 | M GreenDAO - Avg: 3
40 | GreenDAO - Avg: 163
41 |
42 | Task WRITE_DATA
43 | M RAW - Avg: 2925
44 | RAW - Avg: 3281
45 |
46 | M ORMLite - Avg: 6898
47 | ORMLite - Avg: 7203
48 |
49 | M GreenDAO - Avg: 1960
50 | GreenDAO - Avg: 2470
51 |
52 | Task READ_DATA
53 | M RAW - Avg: 803
54 | RAW - Avg: 808
55 |
56 | M ORMLite - Avg: 1656
57 | ORMLite - Avg: 1729
58 |
59 | M GreenDAO - Avg: 1183
60 | GreenDAO - Avg: 1186
61 |
62 | Task READ_INDEXED
63 | M RAW - Avg: 1
64 | RAW - Avg: 1
65 |
66 | M ORMLite - Avg: 2
67 | ORMLite - Avg: 3
68 |
69 | M GreenDAO - Avg: 1
70 | GreenDAO - Avg: 1
71 |
72 | Task READ_SEARCH
73 | M RAW - Avg: 8
74 | RAW - Avg: 8
75 |
76 | M ORMLite - Avg: 119
77 | ORMLite - Avg: 156
78 |
79 | M GreenDAO - Avg: 7
80 | GreenDAO - Avg: 6
81 |
82 | Task DROP_DB
83 | M RAW - Avg: 8
84 | RAW - Avg: 515
85 |
86 | M ORMLite - Avg: 10
87 | ORMLite - Avg: 558
88 |
89 | M GreenDAO - Avg: 8
90 | GreenDAO - Avg: 369
91 |
92 |
93 | ##Screenshots
94 |
95 | 
96 |
97 | After pressing "Run Benchmark" you can press "Show Results" to see the results:
98 |
99 | 
100 |
101 | ##Technical Reference
102 | ###Customizing Benchmark Tests
103 |
104 | - Enable/disable the usage of [in-memory](https://www.sqlite.org/inmemorydb.html) SQLite databases. Check [MainActivity#USE_IN_MEMORY_DB](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/MainActivity.java#L38)
105 | - Number of times to run the tests. Check [MainActivity#NUM_ITERATIONS](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/MainActivity.java#L40)
106 | - Implementing your own [BenchmarkExecutable](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java) you can add more tests.
107 | - Search term. Check [BenchmarkExecutable#SEARCH_TERM](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java#L9)
108 | - Search limit. Check [BenchmarkExecutable#SEARCH_LIMIT](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java#L11)
109 | - Number of users to be saved into the db. Check [BenchmarkExecutable#NUM_USER_INSERTS](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java#L15)
110 | - Number of messages to be saved into the db. Check [BenchmarkExecutable#NUM_MESSAGE_INSERTS](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java#L17)
111 | - Number of messages with readers. Check [BenchmarkExecutable#NUM_MESSAGES_WITH_READERS](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java#L19)
112 | - Number of reades on messages. Check [BenchmarkExecutable#NUM_READERS](/ORM-Benchmark/src/main/java/com/littleinc/orm_benchmark/BenchmarkExecutable.java#L13)
113 |
114 | ###Changing The GreenDao Tests
115 |
116 | GreenDao requires a separate project to generate the source code for database entities and DAOs. The ORM-Benchmark-GreenDAO-Generator project is a Java application that you can run to regenerate the database definitions. You only need to do this if you want to change the GreenDao database model!
117 |
118 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.0.1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
--------------------------------------------------------------------------------
/screenshots/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daj/android-orm-benchmark/2d860f2a9d769bad3d059102d37d84993780aeb6/screenshots/main.png
--------------------------------------------------------------------------------
/screenshots/results.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daj/android-orm-benchmark/2d860f2a9d769bad3d059102d37d84993780aeb6/screenshots/results.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':ORM-Benchmark', ':GreenDAO-Generator'
2 |
--------------------------------------------------------------------------------