Small database efficiency tweaks (#7058)

- When checking whether there is a subscription, there is no need to create feed objects (plus counters etc). Just the number of episodes is enough.
- Downloads section only needs to load the items it actually displays.
- No need to load FeedMedia, just to load FeedItem including the same FeedMedia afterwards.
- No need to convert columns to Strings and back to Longs.
- No need to join favorites when we are only interested in the list of IDs anyway.
This commit is contained in:
ByteHamster 2024-04-04 21:58:36 +02:00 committed by GitHub
parent e894ff1ccb
commit 0288d4e51e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 29 additions and 47 deletions

View File

@ -19,6 +19,7 @@ import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentContainerView;
import de.danoeh.antennapod.model.feed.FeedItemFilter;
import de.danoeh.antennapod.net.download.serviceinterface.FeedUpdateManager;
import de.danoeh.antennapod.ui.echo.EchoConfig;
import de.danoeh.antennapod.ui.screen.home.sections.AllowNotificationsSection;
@ -44,7 +45,6 @@ import de.danoeh.antennapod.databinding.HomeFragmentBinding;
import de.danoeh.antennapod.event.FeedListUpdateEvent;
import de.danoeh.antennapod.event.FeedUpdateRunningEvent;
import de.danoeh.antennapod.ui.screen.SearchFragment;
import de.danoeh.antennapod.storage.preferences.UserPreferences;
import de.danoeh.antennapod.ui.view.LiftOnScrollListener;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
@ -193,14 +193,12 @@ public class HomeFragment extends Fragment implements Toolbar.OnMenuItemClickLis
if (disposable != null) {
disposable.dispose();
}
disposable = Observable.fromCallable(() ->
DBReader.getNavDrawerData(UserPreferences.getSubscriptionsFilter(),
UserPreferences.getFeedOrder(), UserPreferences.getFeedCounterSetting()).items.size())
disposable = Observable.fromCallable(() -> DBReader.getTotalEpisodeCount(FeedItemFilter.unfiltered()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(numSubscriptions -> {
viewBinding.welcomeContainer.setVisibility(numSubscriptions == 0 ? View.VISIBLE : View.GONE);
viewBinding.homeContainer.setVisibility(numSubscriptions == 0 ? View.GONE : View.VISIBLE);
.subscribe(numEpisodes -> {
viewBinding.welcomeContainer.setVisibility(numEpisodes == 0 ? View.VISIBLE : View.GONE);
viewBinding.homeContainer.setVisibility(numEpisodes == 0 ? View.GONE : View.VISIBLE);
}, error -> Log.e(TAG, Log.getStackTraceString(error)));
}

View File

@ -124,14 +124,11 @@ public class DownloadsSection extends HomeSection {
disposable.dispose();
}
SortOrder sortOrder = UserPreferences.getDownloadsSortedOrder();
disposable = Observable.fromCallable(() -> DBReader.getEpisodes(0, Integer.MAX_VALUE,
disposable = Observable.fromCallable(() -> DBReader.getEpisodes(0, NUM_EPISODES,
new FeedItemFilter(FeedItemFilter.DOWNLOADED), sortOrder))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(downloads -> {
if (downloads.size() > NUM_EPISODES) {
downloads = downloads.subList(0, NUM_EPISODES);
}
items = downloads;
adapter.setDummyViews(0);
adapter.updateItems(items);

View File

@ -246,7 +246,7 @@ public class DbWriterTest {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertEquals(0, c.getCount());
c.close();
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
c = adapter.getFeedItemFromMediaIdCursor(item.getMedia().getId());
assertEquals(0, c.getCount());
c.close();
}
@ -370,7 +370,7 @@ public class DbWriterTest {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertEquals(0, c.getCount());
c.close();
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
c = adapter.getFeedItemFromMediaIdCursor(item.getMedia().getId());
assertEquals(0, c.getCount());
c.close();
}
@ -422,7 +422,7 @@ public class DbWriterTest {
c = adapter.getFeedItemCursor(String.valueOf(item.getId()));
assertEquals(0, c.getCount());
c.close();
c = adapter.getSingleFeedMediaCursor(item.getMedia().getId());
c = adapter.getFeedItemFromMediaIdCursor(item.getMedia().getId());
assertEquals(0, c.getCount());
c.close();
}

View File

@ -29,7 +29,6 @@ import de.danoeh.antennapod.storage.database.mapper.ChapterCursor;
import de.danoeh.antennapod.storage.database.mapper.DownloadResultCursor;
import de.danoeh.antennapod.storage.database.mapper.FeedCursor;
import de.danoeh.antennapod.storage.database.mapper.FeedItemCursor;
import de.danoeh.antennapod.storage.database.mapper.FeedMediaCursor;
/**
* Provides methods for reading data from the AntennaPod database.
@ -223,7 +222,7 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
try (Cursor cursor = adapter.getFavoritesIdsCursor(0, Integer.MAX_VALUE)) {
try (Cursor cursor = adapter.getFavoritesIdsCursor()) {
LongList favoriteIDs = new LongList(cursor.getCount());
while (cursor.moveToNext()) {
favoriteIDs.add(cursor.getLong(0));
@ -511,20 +510,13 @@ public final class DBReader {
PodDBAdapter adapter = PodDBAdapter.getInstance();
adapter.open();
try (FeedMediaCursor mediaCursor = new FeedMediaCursor(adapter.getSingleFeedMediaCursor(mediaId))) {
if (!mediaCursor.moveToFirst()) {
try (FeedItemCursor itemCursor = new FeedItemCursor(adapter.getFeedItemFromMediaIdCursor(mediaId))) {
if (!itemCursor.moveToFirst()) {
return null;
}
int indexFeedItem = mediaCursor.getColumnIndex(PodDBAdapter.KEY_FEEDITEM);
long itemId = mediaCursor.getLong(indexFeedItem);
FeedMedia media = mediaCursor.getFeedMedia();
FeedItem item = getFeedItem(itemId);
if (item != null) {
media.setItem(item);
item.setMedia(media);
}
return media;
FeedItem item = itemCursor.getFeedItem();
loadAdditionalFeedItemListData(Collections.singletonList(item));
return item.getMedia();
} finally {
adapter.close();
}
@ -623,13 +615,13 @@ public final class DBReader {
while (cursor.moveToNext()) {
Feed feed = cursor.getFeed();
long feedPlayedTime = Long.parseLong(cursor.getString(indexPlayedTime)) / 1000;
long feedTotalTime = Long.parseLong(cursor.getString(indexTotalTime)) / 1000;
long episodes = Long.parseLong(cursor.getString(indexNumEpisodes));
long episodesStarted = Long.parseLong(cursor.getString(indexEpisodesStarted));
long totalDownloadSize = Long.parseLong(cursor.getString(indexDownloadSize));
long episodesDownloadCount = Long.parseLong(cursor.getString(indexNumDownloaded));
long oldestDate = Long.parseLong(cursor.getString(indexOldestDate));
long feedPlayedTime = cursor.getLong(indexPlayedTime) / 1000;
long feedTotalTime = cursor.getLong(indexTotalTime) / 1000;
long episodes = cursor.getLong(indexNumEpisodes);
long episodesStarted = cursor.getLong(indexEpisodesStarted);
long totalDownloadSize = cursor.getLong(indexDownloadSize);
long episodesDownloadCount = cursor.getLong(indexNumDownloaded);
long oldestDate = cursor.getLong(indexOldestDate);
if (episodes > 0 && oldestDate < Long.MAX_VALUE) {
result.oldestDate = Math.min(result.oldestDate, oldestDate);
@ -648,7 +640,7 @@ public final class DBReader {
adapter.open();
try (Cursor cursor = adapter.getTimeBetweenReleaseAndPlayback(timeFilterFrom, timeFilterTo)) {
cursor.moveToFirst();
long result = Long.parseLong(cursor.getString(0));
long result = cursor.getLong(0);
adapter.close();
return result;
}

View File

@ -1043,14 +1043,9 @@ public class PodDBAdapter {
return db.rawQuery(query, null);
}
public final Cursor getFavoritesIdsCursor(int offset, int limit) {
// Way faster than selecting all columns
final String query = "SELECT " + TABLE_NAME_FEED_ITEMS + "." + KEY_ID
+ " FROM " + TABLE_NAME_FEED_ITEMS
+ " INNER JOIN " + TABLE_NAME_FAVORITES
+ " ON " + TABLE_NAME_FEED_ITEMS + "." + KEY_ID + " = " + TABLE_NAME_FAVORITES + "." + KEY_FEEDITEM
+ " ORDER BY " + TABLE_NAME_FEED_ITEMS + "." + KEY_PUBDATE + " DESC"
+ " LIMIT " + offset + ", " + limit;
public final Cursor getFavoritesIdsCursor() {
final String query = "SELECT " + TABLE_NAME_FAVORITES + "." + KEY_FEEDITEM
+ " FROM " + TABLE_NAME_FAVORITES;
return db.rawQuery(query, null);
}
@ -1109,9 +1104,9 @@ public class PodDBAdapter {
return "((" + SELECT_KEY_ITEM_ID + " * " + seed + ") % 46471)";
}
public final Cursor getSingleFeedMediaCursor(long id) {
final String query = "SELECT " + KEYS_FEED_MEDIA + " FROM " + TABLE_NAME_FEED_MEDIA
+ " WHERE " + KEY_ID + "=" + id;
public final Cursor getFeedItemFromMediaIdCursor(long mediaId) {
final String query = SELECT_FEED_ITEMS_AND_MEDIA
+ " WHERE " + SELECT_KEY_MEDIA_ID + " = " + mediaId;
return db.rawQuery(query, null);
}