mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-26 01:17:00 +02:00
fix: make project ui query optimized (#8961)
From 13 seconds to 0.1 seconds. 1. Joining 1 million events to projects/features is slow. **Solved by using CTE.** 2. Running grouping on 1 million rows is slow. **Solved by adding index.**
This commit is contained in:
parent
c3f50263c8
commit
17d3b5c2fb
@ -46,6 +46,7 @@ afterAll(async () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await projectStore.deleteAll();
|
await projectStore.deleteAll();
|
||||||
await flagStore.deleteAll();
|
await flagStore.deleteAll();
|
||||||
|
await eventStore.deleteAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("it doesn't count flags multiple times when they have multiple events associated with them", async () => {
|
test("it doesn't count flags multiple times when they have multiple events associated with them", async () => {
|
||||||
|
@ -83,7 +83,14 @@ export class ProjectReadModel implements IProjectReadModel {
|
|||||||
userId?: number,
|
userId?: number,
|
||||||
): Promise<ProjectForUi[]> {
|
): Promise<ProjectForUi[]> {
|
||||||
const projectTimer = this.timer('getProjectsForAdminUi');
|
const projectTimer = this.timer('getProjectsForAdminUi');
|
||||||
let projects = this.db(TABLE)
|
let projects = this.db
|
||||||
|
.with('latest_events', (qb) => {
|
||||||
|
qb.select('project', 'feature_name')
|
||||||
|
.max('created_at as last_updated')
|
||||||
|
.whereNotNull('feature_name')
|
||||||
|
.from('events')
|
||||||
|
.groupBy('project', 'feature_name');
|
||||||
|
})
|
||||||
.leftJoin('features', 'features.project', 'projects.id')
|
.leftJoin('features', 'features.project', 'projects.id')
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
'last_seen_at_metrics',
|
'last_seen_at_metrics',
|
||||||
@ -95,13 +102,14 @@ export class ProjectReadModel implements IProjectReadModel {
|
|||||||
'project_settings.project',
|
'project_settings.project',
|
||||||
'projects.id',
|
'projects.id',
|
||||||
)
|
)
|
||||||
.leftJoin('events', (join) => {
|
.leftJoin('latest_events', (join) => {
|
||||||
join.on('events.feature_name', '=', 'features.name').andOn(
|
join.on(
|
||||||
'events.project',
|
'latest_events.feature_name',
|
||||||
'=',
|
'=',
|
||||||
'projects.id',
|
'features.name',
|
||||||
);
|
).andOn('latest_events.project', '=', 'projects.id');
|
||||||
})
|
})
|
||||||
|
.from(TABLE)
|
||||||
.orderBy('projects.name', 'asc');
|
.orderBy('projects.name', 'asc');
|
||||||
|
|
||||||
if (query?.archived === true) {
|
if (query?.archived === true) {
|
||||||
@ -122,7 +130,7 @@ export class ProjectReadModel implements IProjectReadModel {
|
|||||||
'projects.id, projects.name, projects.description, projects.health, projects.created_at, ' +
|
'projects.id, projects.name, projects.description, projects.health, projects.created_at, ' +
|
||||||
'count(DISTINCT features.name) FILTER (WHERE features.archived_at is null) AS number_of_features, ' +
|
'count(DISTINCT features.name) FILTER (WHERE features.archived_at is null) AS number_of_features, ' +
|
||||||
'MAX(last_seen_at_metrics.last_seen_at) AS last_usage, ' +
|
'MAX(last_seen_at_metrics.last_seen_at) AS last_usage, ' +
|
||||||
'MAX(events.created_at) AS last_updated',
|
'MAX(latest_events.last_updated) AS last_updated',
|
||||||
),
|
),
|
||||||
'project_settings.project_mode',
|
'project_settings.project_mode',
|
||||||
'projects.archived_at',
|
'projects.archived_at',
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
exports.up = function (db, callback) {
|
||||||
|
db.runSql(
|
||||||
|
`
|
||||||
|
CREATE INDEX idx_events_project_feature_created
|
||||||
|
ON events (project, feature_name, created_at DESC);
|
||||||
|
`,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.down = function (db, callback) {
|
||||||
|
db.runSql(
|
||||||
|
`
|
||||||
|
DROP INDEX idx_events_project_feature_created;
|
||||||
|
`,
|
||||||
|
callback,
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user