From c9f03f2a2e3805f2c43115aafb92e398b3c0657c Mon Sep 17 00:00:00 2001 From: Menci Date: Wed, 7 Nov 2018 15:01:31 +0800 Subject: [PATCH] Fix slow query on large page of judge_state --- models/common.js | 27 +++++++++++++++++++++++++-- modules/submission.js | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/models/common.js b/models/common.js index 5b68fc9..2d05dd0 100644 --- a/models/common.js +++ b/models/common.js @@ -99,7 +99,7 @@ class Model { return this.model.count({ where: where }); } - static async query(paginate, where, order) { + static async query(paginate, where, order, largeData) { let records = []; if (typeof paginate === 'string') { @@ -121,11 +121,34 @@ class Model { options.limit = parseInt(paginate.perPage); } - records = await this.model.findAll(options); + if (!largeData) records = await this.model.findAll(options); + else { + let sql = await getSqlFromFindAll(this.model, options); + let i = sql.indexOf('FROM'); + sql = 'SELECT id ' + sql.substr(i, sql.length - i); + sql = `SELECT a.* FROM (${sql}) AS b JOIN ${this.model.name} AS a ON a.id = b.id ORDER BY id DESC`; + records = await syzoj.db.query(sql, { model: this.model }); + } } return records.mapAsync(record => (this.fromRecord(record))); } } +function getSqlFromFindAll(Model, options) { + let id = require('uuid')(); + + return new Promise((resolve, reject) => { + Model.addHook('beforeFindAfterOptions', id, options => { + Model.removeHook('beforeFindAfterOptions', id); + + resolve(Model.sequelize.dialect.QueryGenerator.selectQuery(Model.getTableName(), options, Model).slice(0, -1)); + + return new Promise(() => {}); + }); + + return Model.findAll(options).catch(reject); + }); +} + module.exports = Model; diff --git a/modules/submission.js b/modules/submission.js index 4502511..a74b10a 100644 --- a/modules/submission.js +++ b/modules/submission.js @@ -113,7 +113,7 @@ app.get('/submissions', async (req, res) => { } let paginate = syzoj.utils.paginate(await JudgeState.count(where), req.query.page, syzoj.config.page.judge_state); - let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']]); + let judge_state = await JudgeState.query(paginate, where, [['id', 'desc']], true); await judge_state.forEachAsync(async obj => obj.loadRelationships());