mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01: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 () => { | ||||
|     await projectStore.deleteAll(); | ||||
|     await flagStore.deleteAll(); | ||||
|     await eventStore.deleteAll(); | ||||
| }); | ||||
| 
 | ||||
| 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, | ||||
|     ): Promise<ProjectForUi[]> { | ||||
|         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( | ||||
|                 'last_seen_at_metrics', | ||||
| @ -95,13 +102,14 @@ export class ProjectReadModel implements IProjectReadModel { | ||||
|                 'project_settings.project', | ||||
|                 'projects.id', | ||||
|             ) | ||||
|             .leftJoin('events', (join) => { | ||||
|                 join.on('events.feature_name', '=', 'features.name').andOn( | ||||
|                     'events.project', | ||||
|             .leftJoin('latest_events', (join) => { | ||||
|                 join.on( | ||||
|                     'latest_events.feature_name', | ||||
|                     '=', | ||||
|                     'projects.id', | ||||
|                 ); | ||||
|                     'features.name', | ||||
|                 ).andOn('latest_events.project', '=', 'projects.id'); | ||||
|             }) | ||||
|             .from(TABLE) | ||||
|             .orderBy('projects.name', 'asc'); | ||||
| 
 | ||||
|         if (query?.archived === true) { | ||||
| @ -122,7 +130,7 @@ export class ProjectReadModel implements IProjectReadModel { | ||||
|                 '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, ' + | ||||
|                     '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', | ||||
|             '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