1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-04-06 06:21:06 +02:00

perf(MySQL): improved connections pool handling

This commit is contained in:
Fabio Di Stasio 2021-05-15 21:47:30 +02:00
parent 854472c7a3
commit 434711a360
3 changed files with 72 additions and 71 deletions

View File

@ -83,8 +83,8 @@ This is a roadmap with major features will come in near future.
#### • ARM #### • ARM
- [ ] Windows - [ ] Windows
- [ ] Linux - [x] Linux
- [ ] MacOS - [x] MacOS
## Translations ## Translations

View File

@ -1,5 +1,5 @@
'use strict'; 'use strict';
import mysql from 'mysql2'; import mysql from 'mysql2/promise';
import { AntaresCore } from '../AntaresCore'; import { AntaresCore } from '../AntaresCore';
import dataTypes from 'common/data-types/mysql'; import dataTypes from 'common/data-types/mysql';
@ -102,8 +102,10 @@ export class MySQLClient extends AntaresCore {
* @memberof MySQLClient * @memberof MySQLClient
*/ */
async connect () { async connect () {
delete this._params.application_name;
if (!this._poolSize) if (!this._poolSize)
this._connection = mysql.createConnection(this._params); this._connection = await mysql.createConnection(this._params);
else { else {
this._connection = mysql.createPool({ this._connection = mysql.createPool({
...this._params, ...this._params,
@ -1273,6 +1275,8 @@ export class MySQLClient extends AntaresCore {
* @memberof MySQLClient * @memberof MySQLClient
*/ */
async raw (sql, args) { async raw (sql, args) {
if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder
args = { args = {
nest: false, nest: false,
details: false, details: false,
@ -1280,15 +1284,15 @@ export class MySQLClient extends AntaresCore {
...args ...args
}; };
if (args.schema && args.schema !== 'public')
await this.use(args.schema);
const nestTables = args.nest ? '.' : false; const nestTables = args.nest ? '.' : false;
const resultsArr = []; const resultsArr = [];
let paramsArr = []; let paramsArr = [];
const queries = args.split ? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm) : [sql]; const queries = args.split ? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm) : [sql];
const isPool = typeof this._connection.getConnection === 'function';
const connection = isPool ? await this._connection.getConnection() : this._connection;
if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder if (args.schema)
await connection.query(`USE \`${args.schema}\``);
for (const query of queries) { for (const query of queries) {
if (!query) continue; if (!query) continue;
@ -1297,87 +1301,85 @@ export class MySQLClient extends AntaresCore {
let keysArr = []; let keysArr = [];
const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => { const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => {
this._connection.query({ sql: query, nestTables }, async (err, response, fields) => { connection.query({ sql: query, nestTables }).then(async ([response, fields]) => {
timeStop = new Date(); timeStop = new Date();
const queryResult = response; const queryResult = response;
if (err) let remappedFields = fields
reject(err); ? fields.map(field => {
else { if (!field || Array.isArray(field))
let remappedFields = fields return false;
? fields.map(field => {
if (!field || Array.isArray(field))
return false;
const type = this._getType(field); const type = this._getType(field);
return {
name: field.orgName,
alias: field.name,
orgName: field.orgName,
schema: field.schema,
table: field.table,
tableAlias: field.table,
orgTable: field.orgTable,
type: type.name,
length: type.length
};
}).filter(Boolean)
: [];
if (args.details) {
let cachedTable;
if (remappedFields.length) {
paramsArr = remappedFields.map(field => {
if (field.orgTable) cachedTable = field.orgTable;// Needed for some queries on information_schema
return { return {
name: field.orgName, table: field.orgTable || cachedTable,
alias: field.name, schema: field.schema || 'INFORMATION_SCHEMA'
orgName: field.orgName,
schema: field.schema,
table: field.table,
tableAlias: field.table,
orgTable: field.orgTable,
type: type.name,
length: type.length
}; };
}).filter(Boolean) }).filter((val, i, arr) => arr.findIndex(el => el.schema === val.schema && el.table === val.table) === i);
: [];
if (args.details) { for (const paramObj of paramsArr) {
let cachedTable; if (!paramObj.table || !paramObj.schema) continue;
if (remappedFields.length) { try { // Column details
paramsArr = remappedFields.map(field => { const response = await this.getTableColumns(paramObj);
if (field.orgTable) cachedTable = field.orgTable;// Needed for some queries on information_schema remappedFields = remappedFields.map(field => {
return { const detailedField = response.find(f => f.name === field.name);
table: field.orgTable || cachedTable, if (detailedField && field.orgTable === paramObj.table && field.schema === paramObj.schema)
schema: field.schema || 'INFORMATION_SCHEMA' field = { ...field, ...detailedField };
}; return field;
}).filter((val, i, arr) => arr.findIndex(el => el.schema === val.schema && el.table === val.table) === i); });
}
catch (err) {
reject(err);
}
for (const paramObj of paramsArr) { try { // Key usage (foreign keys)
if (!paramObj.table || !paramObj.schema) continue; const response = await this.getKeyUsage(paramObj);
keysArr = keysArr ? [...keysArr, ...response] : response;
try { // Column details }
const response = await this.getTableColumns(paramObj); catch (err) {
remappedFields = remappedFields.map(field => { reject(err);
const detailedField = response.find(f => f.name === field.name);
if (detailedField && field.orgTable === paramObj.table && field.schema === paramObj.schema)
field = { ...field, ...detailedField };
return field;
});
}
catch (err) {
reject(err);
}
try { // Key usage (foreign keys)
const response = await this.getKeyUsage(paramObj);
keysArr = keysArr ? [...keysArr, ...response] : response;
}
catch (err) {
reject(err);
}
} }
} }
} }
resolve({
duration: timeStop - timeStart,
rows: Array.isArray(queryResult) ? queryResult.some(el => Array.isArray(el)) ? [] : queryResult : false,
report: !Array.isArray(queryResult) ? queryResult : false,
fields: remappedFields,
keys: keysArr
});
} }
});
resolve({
duration: timeStop - timeStart,
rows: Array.isArray(queryResult) ? queryResult.some(el => Array.isArray(el)) ? [] : queryResult : false,
report: !Array.isArray(queryResult) ? queryResult : false,
fields: remappedFields,
keys: keysArr
});
}).catch(reject);
}); });
resultsArr.push({ rows, report, fields, keys, duration }); resultsArr.push({ rows, report, fields, keys, duration });
} }
if (isPool) connection.release();
return resultsArr.length === 1 ? resultsArr[0] : resultsArr; return resultsArr.length === 1 ? resultsArr[0] : resultsArr;
} }
} }

View File

@ -368,7 +368,6 @@ export default {
}, },
setNull () { setNull () {
const row = this.localResults.find(row => this.selectedRows.includes(row._id)); const row = this.localResults.find(row => this.selectedRows.includes(row._id));
delete row._id;
const params = { const params = {
primary: this.primaryField.name, primary: this.primaryField.name,