realm / realm-java

Realm is a mobile database: a replacement for SQLite & ORMs
http://realm.io
Apache License 2.0
11.44k stars 1.75k forks source link

use sort query slowly #6048

Closed way1001 closed 2 years ago

way1001 commented 6 years ago

Realm version(s): 5.3.1

Realm sync feature enabled: no

Android Studio version: 3.0.0

Which Android version and device: android N, Allwinner H6

hi, every one

i have a table 180000 records ,no relationships ,not encrypted .

public class Song extends RealmObject implements Serializable {
    public String songBM;
    public String songName;
    public String singer;
    public int songType;
    public int singingProgram;//act program
    public int lang;
    public String path;
    public String fileName;
    public String spell;
    public long zs;
    @Index
    public long orderTimes;
    public long musicTrack;
    public long maxVol;
    public long minVol;
    public long volume;
    public int cloud;
    public long mediaInfo;
    public long movie;
    public long newSong;
    public Date createAT;
}

The query return paged show_limit = 6. it not add sort use 120ms but add sort("orderTimes") query time 2300ms

public  List<Song> getAllKsong(final Query q,Realm realm) {
        final Query query;
        if(!PhoneInfo.isOnline(App.getInstance().getApplicationContext())){
            query = (Query) q.clone();
            query.cloud = KtvAddPlay.NATIVE; //lessthan so this set cloud
        } else {
            query = (Query) q.clone();
            query.cloud = KtvAddPlay.ALL;
        }

        List<Song> ret = new ArrayList<>();
        long start = System.currentTimeMillis();
        RealmResults<Song> results = realm.where(Song.class)
                .beginsWith("spell",query.spell)
                .contains("songName",query.songName)
                .lessThanOrEqualTo("cloud",query.cloud)
                .findAll();

        OrderedRealmCollectionSnapshot<Song> resultsSnapshot = results.createSnapshot();
        if (resultsSnapshot.size() == 0){
            return ret;
        }
        try {
            for (int i = query.startIndex; i < query.startIndex + query.show_limit; i++) {

                if (i >= resultsSnapshot.size()) {
                    break;
                }
                Song temp = realm.copyFromRealm(resultsSnapshot.get(i));
                ret.add(temp);

            }
            long end = System.currentTimeMillis();
            long time = end - start;
            Log.e("TTTTTTT", time + "ms");
            return ret;
        }catch (Exception e){
            e.printStackTrace();
        }
        return ret;
    }

Then i changed it , query time 2100ms

public  List<Song> getAllKsong(final Query q,Realm realm) {
        List<Song> ret = new ArrayList<>();
        long start = System.currentTimeMillis();
        RealmResults<Song> results = realm.where(Song.class)
                                .sort("orderTimes")
                .findAll();
        OrderedRealmCollectionSnapshot<Song> resultsSnapshot = results.createSnapshot();
        if (resultsSnapshot.size() == 0){
            return ret;
        }
        try {
            for (int i = query.startIndex; i < query.startIndex + query.show_limit; i++) {

                if (i >= resultsSnapshot.size()) {
                    break;
                }
                Song temp = realm.copyFromRealm(resultsSnapshot.get(i));
                ret.add(temp);

            }
            long end = System.currentTimeMillis();
            long time = end - start;
            Log.e("TTTTTTT", time + "ms");
            return ret;
        }catch (Exception e){
            e.printStackTrace();
        }
        return ret;
    }

How to improve speed??

nhachicha commented 6 years ago

The second query

realm.where(Song.class)
                                .sort("orderTimes")
                .findAll();

will fetch all 180K elements (sorted) + you're measuring the time to copy/detach every element which shouldn't be part of the measurement (for both queries)

Using contains in the query is very expensive as it needs to scan the whole String, would it be possible to change it to equalTo or startsWith?

realm-probot[bot] commented 6 years ago

Hey - looks like you forgot to add a T:* label - could you please add one? :thumbsup:

way1001 commented 6 years ago

@nhachicha Thanks for your detailed reply,and also know is not a performance problem. I need to query a real time rankings,so need to sort the whole records; used createSnapshot primarily for testing; query data directly for UI display, which will definitely use asynchronous. but 2 seconds of delay is slow So far i haven‘t thought of a good query