1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-26 22:41:17 +02:00

Server: Fix severe performance issue for certain delta calls

This commit is contained in:
Laurent Cozic
2023-11-16 12:02:01 +00:00
parent d0955b4ca2
commit f698068587

View File

@@ -1,6 +1,6 @@
import { Knex } from 'knex'; import { Knex } from 'knex';
import Logger from '@joplin/utils/Logger'; import Logger from '@joplin/utils/Logger';
import { SqliteMaxVariableNum } from '../db'; import { SqliteMaxVariableNum, isPostgres } from '../db';
import { Change, ChangeType, Item, Uuid } from '../services/database/types'; import { Change, ChangeType, Item, Uuid } from '../services/database/types';
import { md5 } from '../utils/crypto'; import { md5 } from '../utils/crypto';
import { ErrorResyncRequired } from '../utils/errors'; import { ErrorResyncRequired } from '../utils/errors';
@@ -191,16 +191,41 @@ export default class ChangeModel extends BaseModel<Change> {
const finalParams = subParams1.concat(subParams2); const finalParams = subParams1.concat(subParams2);
// For Postgres, we need to use materialized tables because, even
// though each independant query is fast, the query planner end up going
// for a very slow plan when they are combined with UNION ALL.
// https://dba.stackexchange.com/a/333147/37012
//
// Normally we could use the same query for SQLite since it supports
// materialized views too, but it doesn't work for some reason so we
// keep the non-optimised query.
if (!doCountQuery) { if (!doCountQuery) {
finalParams.push(limit); finalParams.push(limit);
query = this.db.raw(` if (isPostgres(this.db)) {
SELECT ${fieldsSql} FROM (${subQuery1}) as sub1 query = this.db.raw(`
UNION ALL WITH cte1 AS MATERIALIZED (
SELECT ${fieldsSql} FROM (${subQuery2}) as sub2 ${subQuery1}
ORDER BY counter ASC )
LIMIT ? , cte2 AS MATERIALIZED (
`, finalParams); ${subQuery2}
)
TABLE cte1
UNION ALL
TABLE cte2
ORDER BY counter ASC
LIMIT ?
`, finalParams);
} else {
query = this.db.raw(`
SELECT ${fieldsSql} FROM (${subQuery1}) as sub1
UNION ALL
SELECT ${fieldsSql} FROM (${subQuery2}) as sub2
ORDER BY counter ASC
LIMIT ?
`, finalParams);
}
} else { } else {
query = this.db.raw(` query = this.db.raw(`
SELECT count(*) as total SELECT count(*) as total