show table row count for MySQL

This commit is contained in:
Jan Prochazka 2022-02-10 16:07:44 +01:00
parent 0debe66dd0
commit 4e221ecd3a
9 changed files with 69 additions and 5 deletions

View File

@ -62,9 +62,10 @@ module.exports = {
delete this.requests[msgid]; delete this.requests[msgid];
}, },
handle_status(conid, database, { status }) { handle_status(conid, database, { status }) {
// console.log('HANDLE SET STATUS', status);
const existing = this.opened.find(x => x.conid == conid && x.database == database); const existing = this.opened.find(x => x.conid == conid && x.database == database);
if (!existing) return; if (!existing) return;
if (existing.status == status) return; if (existing.status && status && existing.status.counter > status.counter) return;
existing.status = status; existing.status = status;
socket.emitChanged(`database-status-changed-${conid}-${database}`); socket.emitChanged(`database-status-changed-${conid}-${database}`);
}, },

View File

@ -18,6 +18,12 @@ let lastStatus = null;
let analysedTime = 0; let analysedTime = 0;
let serverVersion; let serverVersion;
let statusCounter = 0;
function getStatusCounter() {
statusCounter += 1;
return statusCounter;
}
async function checkedAsyncCall(promise) { async function checkedAsyncCall(promise) {
try { try {
const res = await promise; const res = await promise;
@ -79,7 +85,7 @@ function handleSyncModel() {
function setStatus(status) { function setStatus(status) {
const statusString = stableStringify(status); const statusString = stableStringify(status);
if (lastStatus != statusString) { if (lastStatus != statusString) {
process.send({ msgtype: 'status', status }); process.send({ msgtype: 'status', status: { ...status, counter: getStatusCounter() } });
lastStatus = statusString; lastStatus = statusString;
} }
} }

View File

@ -8,6 +8,26 @@ const STRUCTURE_FIELDS = ['tables', 'collections', 'views', 'matviews', 'functio
const fp_pick = arg => array => _pick(array, arg); const fp_pick = arg => array => _pick(array, arg);
function mergeTableRowCounts(info: DatabaseInfo, rowCounts): DatabaseInfo {
return {
...info,
tables: (info.tables || []).map(table => ({
...table,
tableRowCount: rowCounts.find(x => x.objectId == table.objectId)?.tableRowCount ?? table.tableRowCount,
})),
};
}
function areDifferentRowCounts(db1: DatabaseInfo, db2: DatabaseInfo) {
for (const t1 of db1.tables || []) {
const t2 = (db2.tables || []).find(x => x.objectId == t1.objectId);
if (t1?.tableRowCount !== t2?.tableRowCount) {
return true;
}
}
return false;
}
export class DatabaseAnalyser { export class DatabaseAnalyser {
structure: DatabaseInfo; structure: DatabaseInfo;
modifications: DatabaseModification[]; modifications: DatabaseModification[];
@ -64,13 +84,29 @@ export class DatabaseAnalyser {
async incrementalAnalysis(structure) { async incrementalAnalysis(structure) {
this.structure = structure; this.structure = structure;
this.modifications = await this.getModifications(); const modifications = await this.getModifications();
if (this.modifications == null) { if (modifications == null) {
// modifications not implemented, perform full analysis // modifications not implemented, perform full analysis
this.structure = null; this.structure = null;
return this.addEngineField(await this._runAnalysis()); return this.addEngineField(await this._runAnalysis());
} }
if (this.modifications.length == 0) return null; const structureModifications = modifications.filter(x => x.action != 'setTableRowCounts');
const setTableRowCounts = modifications.find(x => x.action == 'setTableRowCounts');
let structureWithRowCounts = null;
if (setTableRowCounts) {
const newStructure = mergeTableRowCounts(structure, setTableRowCounts.rowCounts);
if (areDifferentRowCounts(structure, newStructure)) {
structureWithRowCounts = newStructure;
}
}
if (structureModifications.length == 0) {
return structureWithRowCounts ? this.addEngineField(structureWithRowCounts) : null;
}
this.modifications = structureModifications;
if (structureWithRowCounts) this.structure = structureWithRowCounts;
console.log('DB modifications detected:', this.modifications); console.log('DB modifications detected:', this.modifications);
return this.addEngineField(this.mergeAnalyseResult(await this._runAnalysis())); return this.addEngineField(this.mergeAnalyseResult(await this._runAnalysis()));
} }
@ -226,6 +262,20 @@ export class DatabaseAnalyser {
} }
} }
const rowCounts = (snapshot.tables || [])
.filter(x => x.tableRowCount != null)
.map(x => ({
objectId: x.objectId,
tableRowCount: x.tableRowCount,
}));
if (rowCounts.length > 0) {
res.push({
action: 'setTableRowCounts',
rowCounts,
});
}
return [..._compact(res), ...this.getDeletedObjects(snapshot)]; return [..._compact(res), ...this.getDeletedObjects(snapshot)];
} }

View File

@ -85,6 +85,7 @@ export interface TableInfo extends DatabaseObjectInfo {
preloadedRows?: any[]; preloadedRows?: any[];
preloadedRowsKey?: string[]; preloadedRowsKey?: string[];
preloadedRowsInsertOnly?: string[]; preloadedRowsInsertOnly?: string[];
tableRowCount?: number | string;
__isDynamicStructure?: boolean; __isDynamicStructure?: boolean;
} }

View File

@ -11,6 +11,7 @@ export interface OpenedDatabaseConnection {
status?: { status?: {
name: string; name: string;
message?: string; message?: string;
counter: number;
}; };
} }

View File

@ -627,6 +627,7 @@
showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin} showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin}
onPin={isPinned ? null : () => pinnedTables.update(list => [...list, data])} onPin={isPinned ? null : () => pinnedTables.update(list => [...list, data])}
onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null} onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null}
extInfo={data.tableRowCount != null ? `${data.tableRowCount} rows` : null}
on:click={() => handleClick()} on:click={() => handleClick()}
on:middleclick={() => handleClick(true)} on:middleclick={() => handleClick(true)}
on:expand on:expand

View File

@ -88,6 +88,7 @@ class Analyser extends DatabaseAnalyser {
columns: columns.rows.filter(col => col.pureName == table.pureName).map(getColumnInfo), columns: columns.rows.filter(col => col.pureName == table.pureName).map(getColumnInfo),
primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, pkColumns.rows), primaryKey: DatabaseAnalyser.extractPrimaryKeys(table, pkColumns.rows),
foreignKeys: DatabaseAnalyser.extractForeignKeys(table, fkColumns.rows), foreignKeys: DatabaseAnalyser.extractForeignKeys(table, fkColumns.rows),
tableRowCount: table.tableRowCount,
indexes: _.uniqBy( indexes: _.uniqBy(
indexes.rows.filter( indexes.rows.filter(
idx => idx =>
@ -163,6 +164,7 @@ class Analyser extends DatabaseAnalyser {
...x, ...x,
objectId: x.pureName, objectId: x.pureName,
contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate, contentHash: _.isDate(x.modifyDate) ? x.modifyDate.toISOString() : x.modifyDate,
tableRowCount: x.tableRowCount,
})), })),
views: tableModificationsQueryData.rows views: tableModificationsQueryData.rows
.filter(x => x.objectType == 'VIEW') .filter(x => x.objectType == 'VIEW')

View File

@ -2,6 +2,7 @@ module.exports = `
select select
TABLE_NAME as pureName, TABLE_NAME as pureName,
TABLE_TYPE as objectType, TABLE_TYPE as objectType,
TABLE_ROWS as tableRowCount,
case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate
from information_schema.tables from information_schema.tables
where TABLE_SCHEMA = '#DATABASE#' where TABLE_SCHEMA = '#DATABASE#'

View File

@ -1,6 +1,7 @@
module.exports = ` module.exports = `
select select
TABLE_NAME as pureName, TABLE_NAME as pureName,
TABLE_ROWS as tableRowCount,
case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate case when ENGINE='InnoDB' then CREATE_TIME else coalesce(UPDATE_TIME, CREATE_TIME) end as modifyDate
from information_schema.tables from information_schema.tables
where TABLE_SCHEMA = '#DATABASE#' and TABLE_TYPE='BASE TABLE' and TABLE_NAME =OBJECT_ID_CONDITION; where TABLE_SCHEMA = '#DATABASE#' and TABLE_TYPE='BASE TABLE' and TABLE_NAME =OBJECT_ID_CONDITION;