Browse Source

Merge pull request #6311 from nocodb/fix/performance-issue

fix: Add upgrader for creating missing LTAR index in metadb projects
pull/6320/head
Raju Udava 1 year ago committed by GitHub
parent
commit
dd437db870
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      packages/nc-gui/components.d.ts
  2. 2
      packages/nocodb/src/modules/global/init-meta-service.provider.ts
  3. 2
      packages/nocodb/src/version-upgrader/NcUpgrader.ts
  4. 168
      packages/nocodb/src/version-upgrader/ncXcdbLTARIndexUpgrader.ts

15
packages/nc-gui/components.d.ts vendored

@ -78,15 +78,12 @@ declare module '@vue/runtime-core' {
AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger'] AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger']
CilFullscreen: typeof import('~icons/cil/fullscreen')['default'] CilFullscreen: typeof import('~icons/cil/fullscreen')['default']
CilFullscreenExit: typeof import('~icons/cil/fullscreen-exit')['default'] CilFullscreenExit: typeof import('~icons/cil/fullscreen-exit')['default']
ClarityColorPickerSolid: typeof import('~icons/clarity/color-picker-solid')['default']
ClaritySuccessLine: typeof import('~icons/clarity/success-line')['default'] ClaritySuccessLine: typeof import('~icons/clarity/success-line')['default']
IcBaselineMoreVert: typeof import('~icons/ic/baseline-more-vert')['default'] IcBaselineMoreVert: typeof import('~icons/ic/baseline-more-vert')['default']
IcOutlineAccessTime: typeof import('~icons/ic/outline-access-time')['default']
IcOutlineInsertDriveFile: typeof import('~icons/ic/outline-insert-drive-file')['default'] IcOutlineInsertDriveFile: typeof import('~icons/ic/outline-insert-drive-file')['default']
IcRoundEdit: typeof import('~icons/ic/round-edit')['default'] IcRoundEdit: typeof import('~icons/ic/round-edit')['default']
IcRoundKeyboardArrowDown: typeof import('~icons/ic/round-keyboard-arrow-down')['default'] IcRoundKeyboardArrowDown: typeof import('~icons/ic/round-keyboard-arrow-down')['default']
IcRoundSearch: typeof import('~icons/ic/round-search')['default'] IcRoundSearch: typeof import('~icons/ic/round-search')['default']
IcRoundStarBorder: typeof import('~icons/ic/round-star-border')['default']
LogosGoogleGmail: typeof import('~icons/logos/google-gmail')['default'] LogosGoogleGmail: typeof import('~icons/logos/google-gmail')['default']
MaterialSymbolsArrowCircleLeftRounded: typeof import('~icons/material-symbols/arrow-circle-left-rounded')['default'] MaterialSymbolsArrowCircleLeftRounded: typeof import('~icons/material-symbols/arrow-circle-left-rounded')['default']
MaterialSymbolsArrowCircleRightRounded: typeof import('~icons/material-symbols/arrow-circle-right-rounded')['default'] MaterialSymbolsArrowCircleRightRounded: typeof import('~icons/material-symbols/arrow-circle-right-rounded')['default']
@ -94,10 +91,7 @@ declare module '@vue/runtime-core' {
MaterialSymbolsChevronRightRounded: typeof import('~icons/material-symbols/chevron-right-rounded')['default'] MaterialSymbolsChevronRightRounded: typeof import('~icons/material-symbols/chevron-right-rounded')['default']
MaterialSymbolsCloseRounded: typeof import('~icons/material-symbols/close-rounded')['default'] MaterialSymbolsCloseRounded: typeof import('~icons/material-symbols/close-rounded')['default']
MaterialSymbolsDarkModeOutline: typeof import('~icons/material-symbols/dark-mode-outline')['default'] MaterialSymbolsDarkModeOutline: typeof import('~icons/material-symbols/dark-mode-outline')['default']
MaterialSymbolsDeleteOutlineRounded: typeof import('~icons/material-symbols/delete-outline-rounded')['default']
MaterialSymbolsFileCopyOutline: typeof import('~icons/material-symbols/file-copy-outline')['default'] MaterialSymbolsFileCopyOutline: typeof import('~icons/material-symbols/file-copy-outline')['default']
MaterialSymbolsGroupOutlineRounded: typeof import('~icons/material-symbols/group-outline-rounded')['default']
MaterialSymbolsInboxOutlineRounded: typeof import('~icons/material-symbols/inbox-outline-rounded')['default']
MaterialSymbolsKeyboardArrowDownRounded: typeof import('~icons/material-symbols/keyboard-arrow-down-rounded')['default'] MaterialSymbolsKeyboardArrowDownRounded: typeof import('~icons/material-symbols/keyboard-arrow-down-rounded')['default']
MaterialSymbolsKeyboardReturn: typeof import('~icons/material-symbols/keyboard-return')['default'] MaterialSymbolsKeyboardReturn: typeof import('~icons/material-symbols/keyboard-return')['default']
MaterialSymbolsLightModeOutline: typeof import('~icons/material-symbols/light-mode-outline')['default'] MaterialSymbolsLightModeOutline: typeof import('~icons/material-symbols/light-mode-outline')['default']
@ -126,23 +120,16 @@ declare module '@vue/runtime-core' {
MdiChatProcessingOutline: typeof import('~icons/mdi/chat-processing-outline')['default'] MdiChatProcessingOutline: typeof import('~icons/mdi/chat-processing-outline')['default']
MdiCheck: typeof import('~icons/mdi/check')['default'] MdiCheck: typeof import('~icons/mdi/check')['default']
MdiChevronDown: typeof import('~icons/mdi/chevron-down')['default'] MdiChevronDown: typeof import('~icons/mdi/chevron-down')['default']
MdiChevronLeft: typeof import('~icons/mdi/chevron-left')['default']
MdiChevronRight: typeof import('~icons/mdi/chevron-right')['default'] MdiChevronRight: typeof import('~icons/mdi/chevron-right')['default']
MdiCircleMedium: typeof import('~icons/mdi/circle-medium')['default'] MdiCircleMedium: typeof import('~icons/mdi/circle-medium')['default']
MdiClose: typeof import('~icons/mdi/close')['default'] MdiClose: typeof import('~icons/mdi/close')['default']
MdiCloseCircleOutline: typeof import('~icons/mdi/close-circle-outline')['default']
MdiCodeTags: typeof import('~icons/mdi/code-tags')['default'] MdiCodeTags: typeof import('~icons/mdi/code-tags')['default']
MdiContentCopy: typeof import('~icons/mdi/content-copy')['default'] MdiContentCopy: typeof import('~icons/mdi/content-copy')['default']
MdiCurrencyUsd: typeof import('~icons/mdi/currency-usd')['default'] MdiCurrencyUsd: typeof import('~icons/mdi/currency-usd')['default']
MdiDatabaseOutline: typeof import('~icons/mdi/database-outline')['default']
MdiDeleteOutline: typeof import('~icons/mdi/delete-outline')['default']
MdiDiscord: typeof import('~icons/mdi/discord')['default'] MdiDiscord: typeof import('~icons/mdi/discord')['default']
MdiDotsHorizontal: typeof import('~icons/mdi/dots-horizontal')['default'] MdiDotsHorizontal: typeof import('~icons/mdi/dots-horizontal')['default']
MdiDotsVertical: typeof import('~icons/mdi/dots-vertical')['default']
MdiEditOutline: typeof import('~icons/mdi/edit-outline')['default']
MdiEye: typeof import('~icons/mdi/eye')['default'] MdiEye: typeof import('~icons/mdi/eye')['default']
MdiFlag: typeof import('~icons/mdi/flag')['default'] MdiFlag: typeof import('~icons/mdi/flag')['default']
MdiFolder: typeof import('~icons/mdi/folder')['default']
MdiHeart: typeof import('~icons/mdi/heart')['default'] MdiHeart: typeof import('~icons/mdi/heart')['default']
MdiKeyStar: typeof import('~icons/mdi/key-star')['default'] MdiKeyStar: typeof import('~icons/mdi/key-star')['default']
MdiLinkVariant: typeof import('~icons/mdi/link-variant')['default'] MdiLinkVariant: typeof import('~icons/mdi/link-variant')['default']
@ -153,8 +140,6 @@ declare module '@vue/runtime-core' {
MdiMicrosoftTeams: typeof import('~icons/mdi/microsoft-teams')['default'] MdiMicrosoftTeams: typeof import('~icons/mdi/microsoft-teams')['default']
MdiMoonFull: typeof import('~icons/mdi/moon-full')['default'] MdiMoonFull: typeof import('~icons/mdi/moon-full')['default']
MdiPlus: typeof import('~icons/mdi/plus')['default'] MdiPlus: typeof import('~icons/mdi/plus')['default']
MdiPlusOutline: typeof import('~icons/mdi/plus-outline')['default']
MdiRefresh: typeof import('~icons/mdi/refresh')['default']
MdiReload: typeof import('~icons/mdi/reload')['default'] MdiReload: typeof import('~icons/mdi/reload')['default']
MdiRocketLaunchOutline: typeof import('~icons/mdi/rocket-launch-outline')['default'] MdiRocketLaunchOutline: typeof import('~icons/mdi/rocket-launch-outline')['default']
MdiScriptTextOutline: typeof import('~icons/mdi/script-text-outline')['default'] MdiScriptTextOutline: typeof import('~icons/mdi/script-text-outline')['default']

2
packages/nocodb/src/modules/global/init-meta-service.provider.ts

@ -27,7 +27,7 @@ export const InitMetaServiceProvider: Provider = {
const config = await NcConfig.createByEnv(); const config = await NcConfig.createByEnv();
// set version // set version
process.env.NC_VERSION = '0108003'; process.env.NC_VERSION = '0111002';
// init cache // init cache
await NocoCache.init(); await NocoCache.init();

2
packages/nocodb/src/version-upgrader/NcUpgrader.ts

@ -15,6 +15,7 @@ import ncProjectEnvUpgrader from './ncProjectEnvUpgrader';
import ncHookUpgrader from './ncHookUpgrader'; import ncHookUpgrader from './ncHookUpgrader';
import ncProjectConfigUpgrader from './ncProjectConfigUpgrader'; import ncProjectConfigUpgrader from './ncProjectConfigUpgrader';
import ncXcdbLTARUpgrader from './ncXcdbLTARUpgrader'; import ncXcdbLTARUpgrader from './ncXcdbLTARUpgrader';
import ncXcdbLTARIndexUpgrader from './ncXcdbLTARIndexUpgrader';
import type { MetaService } from '~/meta/meta.service'; import type { MetaService } from '~/meta/meta.service';
import type { NcConfig } from '~/interface/config'; import type { NcConfig } from '~/interface/config';
@ -142,6 +143,7 @@ export default class NcUpgrader {
{ name: '0105004', handler: ncHookUpgrader }, { name: '0105004', handler: ncHookUpgrader },
{ name: '0107004', handler: ncProjectConfigUpgrader }, { name: '0107004', handler: ncProjectConfigUpgrader },
{ name: '0108002', handler: ncXcdbLTARUpgrader }, { name: '0108002', handler: ncXcdbLTARUpgrader },
{ name: '0111002', handler: ncXcdbLTARIndexUpgrader },
]; ];
} }
} }

168
packages/nocodb/src/version-upgrader/ncXcdbLTARIndexUpgrader.ts

@ -0,0 +1,168 @@
import { Logger } from '@nestjs/common';
import { RelationTypes, UITypes } from 'nocodb-sdk';
import type { LinkToAnotherRecordColumn } from '~/models';
import type { MetaService } from '~/meta/meta.service';
import type { NcUpgraderCtx } from './NcUpgrader';
import { MetaTable } from '~/utils/globals';
import { Base } from '~/models';
import NcConnectionMgrv2 from '~/utils/common/NcConnectionMgrv2';
import { Model } from '~/models';
const logger = new Logger('LTARIndexUpgrader');
// An upgrader for adding missing index of LTAR relations in XCDB bases
async function upgradeModelRelationsIndex({
model,
indexes,
ncMeta,
sqlClient,
}: {
ncMeta: MetaService;
model: Model;
sqlClient: ReturnType<
(typeof NcConnectionMgrv2)['getSqlClient']
> extends Promise<infer U>
? U
: ReturnType<(typeof NcConnectionMgrv2)['getSqlClient']>;
indexes: {
cn: string;
key_name: string;
type: string;
rqd: boolean | number;
cst: string;
cstn: string;
}[];
}) {
// Iterate over each column and upgrade LTAR
for (const column of await model.getColumns(ncMeta)) {
if (column.uidt !== UITypes.LinkToAnotherRecord) {
continue;
}
const colOptions = await column.getColOptions<LinkToAnotherRecordColumn>(
ncMeta,
);
// if colOptions not found then skip
if (!colOptions) {
continue;
}
switch (colOptions.type) {
// use belongs to since child column belongs to current table in that case
case RelationTypes.BELONGS_TO:
{
// const parentCol = await colOptions.getParentColumn(ncMeta);
const childCol = await colOptions.getChildColumn(ncMeta);
// const parentModel = await parentCol.getModel(ncMeta);
const childModel = await childCol.getModel(ncMeta);
// check index already exists or not
const indexExists = indexes.find((index) => {
return index.cn === childCol.column_name;
});
if (indexExists) {
continue;
}
logger.log(`Creating index for column '${childCol.column_name}'`);
// create a new index for the column
const indexArgs = {
columns: [childCol.column_name],
tn: childModel.table_name,
non_unique: true,
};
await sqlClient.indexCreate(indexArgs);
}
break;
}
}
}
// An upgrader for adding missing index for LTAR relations in XCDB bases
async function upgradeBaseRelations({
ncMeta,
base,
}: {
ncMeta: MetaService;
base: Base;
}) {
const sqlClient = await NcConnectionMgrv2.getSqlClient(base, ncMeta.knex);
// get models for the base
const models = await ncMeta.metaList2(null, base.id, MetaTable.MODELS);
// get all columns and filter out relations and create index if not exists
for (const model of models) {
logger.log(`Upgrading model '${model.title}'`);
logger.log(`Fetching index list of model '${model.title}'`);
const indexes = await sqlClient.indexList({
tn: model.table_name,
});
const indexList = indexes.data?.list ?? [];
// exclude composite indexes
const filteredIndexList = indexList.filter((indexObj, i) => {
return indexList.every((indexObj2, j) => {
if (i === j) return true;
return indexObj2.key_name !== indexObj.key_name;
});
});
await upgradeModelRelationsIndex({
ncMeta,
model: new Model(model),
sqlClient,
indexes: filteredIndexList,
});
logger.log(`Upgraded model '${model.title}'`);
}
}
// Add missing index for LTAR relations
export default async function ({ ncMeta }: NcUpgraderCtx) {
logger.log(
'Starting upgrade for LTAR relations in XCDB bases to add missing index',
);
// get all xcdb bases
const bases = await ncMeta.metaList2(null, null, MetaTable.BASES, {
condition: {
is_meta: 1,
},
orderBy: {},
});
if (!bases.length) return;
// iterate and upgrade each base
for (const _base of bases) {
const base = new Base(_base);
// skip if not pg, since for other db we don't need to upgrade
if (ncMeta.knex.clientType() !== 'pg') {
continue;
}
const project = await base.getProject(ncMeta);
// skip deleted projects
if (!project || project.deleted) continue;
logger.log(`Upgrading base '${base.alias}'(${project.title})`);
await upgradeBaseRelations({
ncMeta,
base,
});
logger.log(`Upgraded base '${base.alias}'(${project.title})`);
}
logger.log(
'Finished upgrade for LTAR relations in XCDB bases to add missing index',
);
}
Loading…
Cancel
Save