Improve performance of suggested version calculation.
The history of this is that #974 identified a problem, which was fixed in !497. That MR added test coverage for the bug. However, the fix for it actually added a huge performance hit, on the order of 30 seconds or so when calculating the suggested version. This fixes that performance problem by removing the need for a sub query. The end goal is to take the following query: ``` UPDATE app SET suggestedVersion = ( SELECT MAX(apk.version) FROM apk WHERE ... ) ``` and the `WHERE` clause needs to somehow join the outer `app` table with the inner `apk` table, such that the repo in question does not matter. It can't just join directly from `apk.appId -> app.rowid`, because the `app` is specific to a given repository, but we want to select the `MAX(apk.version)` from every related apk, regardless of repo. This commit solves it by joining the inner `apk` table onto an intermediate `app` table, which is used purely so that we can select apks where their `packageId` is the same as the `packageId` of the app being updated.
This commit is contained in:
parent
833ae329e4
commit
aae0a57dfe
@ -953,6 +953,8 @@ public class AppProvider extends FDroidProvider {
|
|||||||
* with the closest version code to that, without going over.
|
* with the closest version code to that, without going over.
|
||||||
* If the app is not compatible at all (i.e. no versions were compatible)
|
* If the app is not compatible at all (i.e. no versions were compatible)
|
||||||
* then we take the highest, otherwise we take the highest compatible version.
|
* then we take the highest, otherwise we take the highest compatible version.
|
||||||
|
*
|
||||||
|
* @see #updateSuggestedFromLatest()
|
||||||
*/
|
*/
|
||||||
private void updateSuggestedFromUpstream() {
|
private void updateSuggestedFromUpstream() {
|
||||||
Utils.debugLog(TAG, "Calculating suggested versions for all apps which specify an upstream version code.");
|
Utils.debugLog(TAG, "Calculating suggested versions for all apps which specify an upstream version code.");
|
||||||
@ -963,12 +965,19 @@ public class AppProvider extends FDroidProvider {
|
|||||||
final boolean unstableUpdates = Preferences.get().getUnstableUpdates();
|
final boolean unstableUpdates = Preferences.get().getUnstableUpdates();
|
||||||
String restrictToStable = unstableUpdates ? "" : (apk + "." + ApkTable.Cols.VERSION_CODE + " <= " + app + "." + Cols.UPSTREAM_VERSION_CODE + " AND ");
|
String restrictToStable = unstableUpdates ? "" : (apk + "." + ApkTable.Cols.VERSION_CODE + " <= " + app + "." + Cols.UPSTREAM_VERSION_CODE + " AND ");
|
||||||
|
|
||||||
|
// The join onto `appForThisApk` is to ensure that the MAX(apk.versionCode) is chosen from
|
||||||
|
// all apps regardless of repo. If we joined directly onto the outer `app` table we are
|
||||||
|
// in the process of updating, then it would be limited to only apks from the same repo.
|
||||||
|
// By adding the extra join, and then joining based on the packageId of this inner app table
|
||||||
|
// and the app table we are updating, we take into account all apks for this app.
|
||||||
|
|
||||||
String updateSql =
|
String updateSql =
|
||||||
"UPDATE " + app + " SET " + Cols.SUGGESTED_VERSION_CODE + " = ( " +
|
"UPDATE " + app + " SET " + Cols.SUGGESTED_VERSION_CODE + " = ( " +
|
||||||
" SELECT MAX( " + apk + "." + ApkTable.Cols.VERSION_CODE + " ) " +
|
" SELECT MAX( " + apk + "." + ApkTable.Cols.VERSION_CODE + " ) " +
|
||||||
" FROM " + apk +
|
" FROM " + apk +
|
||||||
|
" JOIN " + app + " AS appForThisApk ON (appForThisApk." + Cols.ROW_ID + " = " + apk + "." + ApkTable.Cols.APP_ID + ") " +
|
||||||
" WHERE " +
|
" WHERE " +
|
||||||
joinToApksRegardlessOfRepo() + " AND " +
|
app + "." + Cols.PACKAGE_ID + " = appForThisApk." + Cols.PACKAGE_ID + " AND " +
|
||||||
restrictToStable +
|
restrictToStable +
|
||||||
" ( " + app + "." + Cols.IS_COMPATIBLE + " = 0 OR " + apk + "." + Cols.IS_COMPATIBLE + " = 1 ) ) " +
|
" ( " + app + "." + Cols.IS_COMPATIBLE + " = 0 OR " + apk + "." + Cols.IS_COMPATIBLE + " = 1 ) ) " +
|
||||||
" WHERE " + Cols.UPSTREAM_VERSION_CODE + " > 0 ";
|
" WHERE " + Cols.UPSTREAM_VERSION_CODE + " > 0 ";
|
||||||
@ -976,29 +985,6 @@ public class AppProvider extends FDroidProvider {
|
|||||||
db().execSQL(updateSql);
|
db().execSQL(updateSql);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that when we select a list of {@link ApkTable} rows for which to calculate the
|
|
||||||
* {@link Cols#SUGGESTED_VERSION_CODE}, that we select all apks belonging to the same package,
|
|
||||||
* regardless of which repo they come from. We can't just join {@link ApkTable} onto the
|
|
||||||
* {@link AppMetadataTable}, because the {@link AppMetadataTable} table is specific to a repo.
|
|
||||||
*
|
|
||||||
* This is required so that apps always have the highest possible
|
|
||||||
* {@link Cols#SUGGESTED_VERSION_CODE}, regardless of the repository priorities. Without this,
|
|
||||||
* then each {@link AppMetadataTable} row will have a different {@link Cols#SUGGESTED_VERSION_CODE}
|
|
||||||
* depending on which repo it came from. With this, each {@link AppMetadataTable} row has the
|
|
||||||
* same {@link Cols#SUGGESTED_VERSION_CODE}, even if that version is from a different repo.
|
|
||||||
*/
|
|
||||||
private String joinToApksRegardlessOfRepo() {
|
|
||||||
final String apk = getApkTableName();
|
|
||||||
final String app = getTableName();
|
|
||||||
|
|
||||||
return app + "." + Cols.PACKAGE_ID + " = (" +
|
|
||||||
" SELECT innerAppName." + Cols.PACKAGE_ID +
|
|
||||||
" FROM " + app + " as innerAppName " +
|
|
||||||
" WHERE innerAppName." + Cols.ROW_ID + " = " + apk + "." + ApkTable.Cols.APP_ID +
|
|
||||||
") ";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We set each app's suggested version to the latest available that is
|
* We set each app's suggested version to the latest available that is
|
||||||
* compatible, or the latest available if none are compatible.
|
* compatible, or the latest available if none are compatible.
|
||||||
@ -1006,6 +992,8 @@ public class AppProvider extends FDroidProvider {
|
|||||||
* If the suggested version is null, it means that we could not figure it
|
* If the suggested version is null, it means that we could not figure it
|
||||||
* out from the upstream vercode. In such a case, fall back to the simpler
|
* out from the upstream vercode. In such a case, fall back to the simpler
|
||||||
* algorithm as if upstreamVercode was 0.
|
* algorithm as if upstreamVercode was 0.
|
||||||
|
*
|
||||||
|
* @see #updateSuggestedFromUpstream()
|
||||||
*/
|
*/
|
||||||
private void updateSuggestedFromLatest() {
|
private void updateSuggestedFromLatest() {
|
||||||
Utils.debugLog(TAG, "Calculating suggested versions for all apps which don't specify an upstream version code.");
|
Utils.debugLog(TAG, "Calculating suggested versions for all apps which don't specify an upstream version code.");
|
||||||
@ -1017,8 +1005,9 @@ public class AppProvider extends FDroidProvider {
|
|||||||
"UPDATE " + app + " SET " + Cols.SUGGESTED_VERSION_CODE + " = ( " +
|
"UPDATE " + app + " SET " + Cols.SUGGESTED_VERSION_CODE + " = ( " +
|
||||||
" SELECT MAX( " + apk + "." + ApkTable.Cols.VERSION_CODE + " ) " +
|
" SELECT MAX( " + apk + "." + ApkTable.Cols.VERSION_CODE + " ) " +
|
||||||
" FROM " + apk +
|
" FROM " + apk +
|
||||||
|
" JOIN " + app + " AS appForThisApk ON (appForThisApk." + Cols.ROW_ID + " = " + apk + "." + ApkTable.Cols.APP_ID + ") " +
|
||||||
" WHERE " +
|
" WHERE " +
|
||||||
joinToApksRegardlessOfRepo() + " AND " +
|
app + "." + Cols.PACKAGE_ID + " = appForThisApk." + Cols.PACKAGE_ID + " AND " +
|
||||||
" ( " + app + "." + Cols.IS_COMPATIBLE + " = 0 OR " + apk + "." + ApkTable.Cols.IS_COMPATIBLE + " = 1 ) ) " +
|
" ( " + app + "." + Cols.IS_COMPATIBLE + " = 0 OR " + apk + "." + ApkTable.Cols.IS_COMPATIBLE + " = 1 ) ) " +
|
||||||
" WHERE COALESCE(" + Cols.UPSTREAM_VERSION_CODE + ", 0) = 0 OR " + Cols.SUGGESTED_VERSION_CODE + " IS NULL ";
|
" WHERE COALESCE(" + Cols.UPSTREAM_VERSION_CODE + ", 0) = 0 OR " + Cols.SUGGESTED_VERSION_CODE + " IS NULL ";
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user