安卓SQLite查询语句速度

3
我希望能够加速一个在我的SQLite数据库中进行的相当简单的查询操作。该查询操作是在大约6500行数据的表格中进行的,目前返回结果需要大约600毫秒。我不知道这是否可以接受,但我原本希望它会更快。最终我会将其放入AsyncTask中,但我想尽可能地进行优化。在下面的代码片段中,您可以看到我已经尝试过的内容。请注意,KEY_songPath已被索引。
public ArrayList<Song> getCurrentDirSongs(String currentDir) {
long startTime = System.currentTimeMillis();
ArrayList<Song> songsList = new ArrayList<Song>();

String selectQuery = "";
int strLength = currentDir.length();
    //selectQuery = "SELECT  * FROM " + TABLE_SONGS + " WHERE (" + KEY_songPath + " >= '" + currentDir + "')";
    //selectQuery = "SELECT  * FROM " + TABLE_SONGS + " WHERE (" + KEY_songPath + " GLOB '" + currentDir + "*')";
    //selectQuery = "SELECT  * FROM " + TABLE_SONGS + " WHERE (" + KEY_songPath + " LIKE '" + currentDir + "%')";
    selectQuery = "SELECT  * FROM " + TABLE_SONGS + " WHERE " + KEY_ID +
                    " IN (SELECT " + KEY_ID +" FROM "+ TABLE_SONGS + " WHERE length(" + KEY_songPath + ")>= "+ strLength +") AND " + 
                    "(" + KEY_songPath + " LIKE '" + currentDir + "%')";

SQLiteDatabase db = this.getReadableDatabase();

Cursor cursor = db.rawQuery(selectQuery, null);

// looping through all rows and adding to list
if (cursor.moveToFirst()) {
    do {
        Song song = new Song();
        song.setSongTitle(cursor.getString(1));
        song.setSongPath(cursor.getString(2));
        song.setSongArtist(cursor.getString(3));
        song.setSongAlbum(cursor.getString(4));
        song.setTrackNumber(cursor.getString(5));
        song.setID(Integer.parseInt(cursor.getString(6)));
        song.setAlbumID(Integer.parseInt(cursor.getString(7)));
        song.setArtistID(Integer.parseInt(cursor.getString(8)));
        song.setSongCheckedStatus(Boolean.parseBoolean(cursor.getString(9)));
        song.setSongPosition(Integer.parseInt(cursor.getString(10)));
        song.setSongDuration(Integer.parseInt(cursor.getString(11)));
        // Adding song to list
        songsList.add(song);
    } while (cursor.moveToNext());
}
long estimatedTime = System.currentTimeMillis() - startTime;
Log.d("AMCDatabase Database Handler: ", "SongsList.size(): "+ getSongsCount("SongsList") + " Time: " + estimatedTime + "ms");
// return contact list
return songsList;

以下是返回的结果: SongsList.size():6390 时间:588毫秒

非常感谢你的帮助!

附言:这可能不是问题 - 在查询和将6000个值添加到ArrayList中,一秒钟的时间是否可接受?


也许我漏掉了什么,但是你第三个被注释的查询语句有什么问题吗?我不确定我理解为什么你要查询KEY_ID然后再基于它进行查询。 - Geobits
嗨Geobits。我只是在随意尝试加速。查询3和4的返回时间相似。想法是创建表的较小子集。 - Mr.Adam
啊。我问的原因是,在你的嵌套查询中,你仍然在完整的6k行上运行“LIKE currentDir%”部分,所以我看不出它如何比第三个更好。无论如何,就像你在更新中说的那样,这可能不是问题。不过很难说什么时间是可以接受的。特别是如果你要异步处理它(你应该这样做),那么对你来说什么是可以接受的呢?我会担心先把所有事情都做完。如果需要,速度稍后再考虑。不过这可能不是查询的问题。在查询之后和循环之前检查计时器以查看你得到了什么。 - Geobits
不是很相关,但你真的应该关闭那个“Cursor”。 - Geobits
你的estimatedTime包括调用getReadableDatabase(),这可能会增加一些开销到你的测量中。你可以通过将long startTime = System.currentTimeMillis();移到执行rawQuery之前来确认这一点。此外,你应该考虑在getCurrentDirSongs()之外的早期时间只执行一次SQLiteDatabase db = this.getReadableDatabase(); - Suraj C
显示剩余2条评论
2个回答

0

尝试不要使用嵌套的SELECT语句,而是看看是否可以使用JOIN

例如:

SELECT * FROM Songs AS s1 JOIN Songs AS s2 ON s1.KEY_ID = s2.KEY_ID WHERE length (s2.KEY_SONGPATH) >= " + strLength + ") AND s1.KEY_SONGPATH LIKE '" + currentDir + "%'

有没有什么建议?在这种情况下规范化数据似乎不合适,我只想通过songPath过滤表格。可以使用临时表吗?您能提供一个例子吗? - Mr.Adam
PaulG,感谢您的示例,非常感谢。但是,它返回的速度稍慢 - 800毫秒。有什么想法吗? - Mr.Adam

0

不要使用子查询,因为它并不能提高速度,因为它仍然需要进行相同的检查。

不要使用 LENGTH(column) >= value,因为它比 LIKE 检查更快,也无法被索引。

为了加速 LIKE,在 KEY_ID 列上放置一个索引。 由于默认情况下 LIKE 是不区分大小写的,所以在创建索引时必须使用 COLLATE NOCASE (请参见 CREATE INDEX documentation)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接