&引用;“优化”;在Android中访问游标:位置与列名
从性能的角度来看:如果在每次访问我的游标时我都使用以下内容,是否可以:&引用;“优化”;在Android中访问游标:位置与列名,android,cursor,Android,Cursor,从性能的角度来看:如果在每次访问我的游标时我都使用以下内容,是否可以: public static final String COLUMN_NAME = "my_column_name"; cursor.getString(cursor.getColumnIndex(COLUMN_NAME)); 或者,如果我改用此选项,我会看到绩效的显著改善: public static final int COLUMN_POSITION = #column_position; cursor.getStrin
public static final String COLUMN_NAME = "my_column_name";
cursor.getString(cursor.getColumnIndex(COLUMN_NAME));
或者,如果我改用此选项,我会看到绩效的显著改善:
public static final int COLUMN_POSITION = #column_position;
cursor.getString(COLUMN_POSITION);
我更喜欢第一种方法,因为代码的其余部分不取决于列在查询中的位置,而只取决于列的名称。所以我的问题是:是否值得牺牲这一点来换取使用恒定位置访问光标的“性能改进”?。您在Android应用程序中更喜欢哪种方法?我想这与Android无关。在SQLite中,通过索引(列位置)访问列应该更快。为了回答您的问题(顺便提一下,我的问题),我做了一些测试 此测试基本上是为了检查这两种情况下查询所用的时间:
cursor.getString(cursor.getColumnIndex(COLUMN_NAME))
方法cursor.getString(column\u POSITION)
方法ContentProvider
结果:
___________________________________________________________________________
| Column count| Time (ms) getColumnIndex | Time (ms) columnId | improvement |
|_____________|__________________________|____________________|_____________|
| 500 | 34564 | 30401 | 13% |
| 200 | 9987 | 8502 | 17% |
| 100 | 4713 | 4004 | 17% |
| 50 | 2400 | 1971 | 21% |
| 20 | 1088 | 915 | 19% |
|___________________________________________________________________________|
因此,首先获取列id并直接调用getString()
方法将花费大约20%更少的时间
试验方法详情: 平台:安卓4.3上的Nexus7(2012) 数据库创建:
public static int TESTSPEEDCOLUMNCOUNT = 200;
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE " + Tables.TESTSPEED + " (");
sb.append(BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, ");
for (int i = 0; i < (TESTSPEEDCOLUMNCOUNT - 1); ++i) {
sb.append("C" + i + " TEXT, ");
}
sb.append("C" + (TESTSPEEDCOLUMNCOUNT - 1) + " TEXT)");
db.execSQL(sb.toString());
我知道,我的问题是:“显著”更快?我不知道确切的数字,但我认为只有在一个表中有100k+列时,差异才会显著。确定这一点的最佳方法是创建一个示例项目,并使用
System.nanoTime()
计算时间差。这确实适用于Android。通过ContentProvider返回的游标不需要SQLite支持。事实上,很多人不是。您可以查看游标的实现,自己来了解。在AbstractCursor.getColumnIndex的快速查看中,如果您有多个列(查找为O(n),其中n是列数),那么您绝对希望自己缓存索引值。在任何一种情况下,您都要调用getString(index)。这里更大的收获是,500列上的getColumnIndex本身需要将近4秒的时间。考虑到getColumnIndex代码的外观,缓存它很容易,也很值得。这个答案现在有点过时了。如果查看SQLiteCursor.java
中getColumnIndex(String columnName)
的源代码,可以看到它们在方法顶部创建了一个字符串(name)到整数(index)的映射。因此,现在每个列、每个表只进行一次列名查找。
public class ProviderTestSpeed extends ProviderTestCase2<MyProvider> {
private ContentValues createElementForId(String id) {
ContentValues cv = new ContentValues();
for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
cv.put("C" + i, id);
}
return cv;
}
public void testSpeed() {
Log.d(TAG, "testSpeed start columnCount = " + columnCount);
ArrayList<ContentValues> list = new ArrayList<ContentValues>();
ContentValues[] tabcv = {};
for (int j = 0; j < 10; ++j) {
list.clear();
for (int i = 0; i < 500; ++i) {
ContentValues cv = createElementForId(String.valueOf(i));
list.add(cv);
}
mContentResolver.bulkInsert(TestSpeedCONTENT_URI, list.toArray(tabcv));
}
Log.d(TAG, "testSpeed insertFinished");
Cursor cursor = mContentResolver.query(TestSpeedCONTENT_URI, null, null, null, null);
cursor.moveToFirst();
Log.d(TAG, "testSpeed itemCount = " + cursor.getCount() + " columnCount=" + cursor.getColumnCount());
// build the tab to avoid dynamic allocation during the mesure
ArrayList<String> listColumns = new ArrayList<String>();
for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
listColumns.add("C" + i);
}
String[] tabColumnsType = {};
String[] tabColumns = listColumns.toArray(tabColumnsType);
Date now = new Date();
long start = now.getTime();
do {
for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
// get the all the columns of the table
cursor.getString(cursor.getColumnIndex(tabColumns[i]));
}
} while (cursor.moveToNext());
now = new Date();
long end = now.getTime();
Log.d(TAG, "testSpeed took " + (end - start) + " with getColumnIndex at each time");
cursor.moveToFirst();
now = new Date();
start = now.getTime();
do {
for (int i = 0; i < TESTSPEEDCOLUMNCOUNT; ++i) {
// get the all the columns of the table using directly the column id
cursor.getString(i);
}
} while (cursor.moveToNext());
now = new Date();
end = now.getTime();
Log.d(TAG, "testSpeed took " + (end - start) + " with getColumnIndex before loop");
}
}
W/CursorWindow(1628): Window is full: requested allocation 2412 bytes, free space 988 bytes, window size 2097152 bytes