perf: flattenedFields sanitized collection/global property, remove deep copying in validateQueryPaths#9299
Conversation
…ep copying for each constraint in `validateQueryPaths`
2aea43e to
6d3503f
Compare
DanRibbens
left a comment
There was a problem hiding this comment.
This looks good! Kind of a pain to change all the names, but I think it would be good to make the name change.
What do you think?
| flattenFields: FlattenField[] | ||
| } & MarkRequired<TabAsField, 'name'> | ||
|
|
||
| export type FlattenField = |
There was a problem hiding this comment.
The name for this type is slightly off for me which hurts readability a bit. I would name it FlattenedField and change that on these other types too. FlattenedArrayField is the result of flattenFields() the function.
| * Fields in the database schema structure | ||
| * Rows / collapsible / tabs w/o name `fields` merged to top, UIs are excluded | ||
| */ | ||
| flattenFields: FlattenField[] |
There was a problem hiding this comment.
I think this should be named flattenedFields to be more clear. flattenFields sounds like a function.
flattenFields sanitized collection/global property, remove deep copying in validateQueryPathsflattenedFields sanitized collection/global property, remove deep copying in validateQueryPaths
| } | ||
|
|
||
| default: { | ||
| if (field.type !== 'ui') { |
There was a problem hiding this comment.
I would have made added case 'ui': break; for easier readability. This is fine since it is one if statement but if you want to make it better you could.
I also would prefer to make use of the utilities/traverseFields as much as possible. Again not a deal breaker though.
…ng in `validateQueryPaths` (#9299) ### What? Improves querying performance of the Local API, reduces copying overhead ### How? Adds `flattenedFields` property for sanitized collection/global config which contains fields in database schema structure. For example, It removes rows / collapsible / unnamed tabs and merges them to the parent `fields`, ignores UI fields, named tabs are added as `type: 'tab'`. This simplifies code in places like Drizzle `transform/traverseFields`. Also, now we can avoid calling `flattenTopLevelFields` which adds some overhead and use `collection.flattenedFields` / `field.flattenedFields`. By refactoring `configToJSONSchema.ts` with `flattenedFields` it also 1. Fixes #9467 2. Fixes types for UI fields were generated for `select` Removes this deep copying for each `where` query constraint https://github.com/payloadcms/payload/blob/58ac784425b411fc28c91dbb3e7df06cc26b6320/packages/payload/src/database/queryValidation/validateQueryPaths.ts#L69-L73 which potentially can add overhead if you have a large collection/global config UPD: The overhead is even much more than in the benchmark below if you have Lexical with blocks. Benchmark in `relationships/int.spec.ts`: ```ts const now = Date.now() for (let i = 0; i < 10; i++) { const now = Date.now() for (let i = 0; i < 300; i++) { const query = await payload.find({ collection: 'chained', where: { 'relation.relation.name': { equals: 'third', }, and: [ { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, ], }, }) } payload.logger.info(`#${i + 1} ${Date.now() - now}`) } payload.logger.info(`Total ${Date.now() - now}`) ``` Before: ``` [02:11:48] INFO: #1 3682 [02:11:50] INFO: #2 2199 [02:11:54] INFO: #3 3483 [02:11:56] INFO: #4 2516 [02:11:59] INFO: #5 2467 [02:12:01] INFO: #6 1987 [02:12:03] INFO: #7 1986 [02:12:05] INFO: #8 2375 [02:12:07] INFO: #9 2040 [02:12:09] INFO: #10 1920 [PASS] Relationships > Querying > Nested Querying > should allow querying two levels deep (24667ms) [02:12:09] INFO: Total 24657 ``` After: ``` [02:12:36] INFO: #1 2113 [02:12:38] INFO: #2 1854 [02:12:40] INFO: #3 1700 [02:12:42] INFO: #4 1797 [02:12:44] INFO: #5 2121 [02:12:46] INFO: #6 1774 [02:12:47] INFO: #7 1670 [02:12:49] INFO: #8 1610 [02:12:50] INFO: #9 1596 [02:12:52] INFO: #10 1576 [PASS] Relationships > Querying > Nested Querying > should allow querying two levels deep (17828ms) [02:12:52] INFO: Total 17818 ```
|
🚀 This is included in version v3.1.1 |
…ng in `validateQueryPaths` (#9299) ### What? Improves querying performance of the Local API, reduces copying overhead ### How? Adds `flattenedFields` property for sanitized collection/global config which contains fields in database schema structure. For example, It removes rows / collapsible / unnamed tabs and merges them to the parent `fields`, ignores UI fields, named tabs are added as `type: 'tab'`. This simplifies code in places like Drizzle `transform/traverseFields`. Also, now we can avoid calling `flattenTopLevelFields` which adds some overhead and use `collection.flattenedFields` / `field.flattenedFields`. By refactoring `configToJSONSchema.ts` with `flattenedFields` it also 1. Fixes #9467 2. Fixes types for UI fields were generated for `select` Removes this deep copying for each `where` query constraint https://github.com/payloadcms/payload/blob/58ac784425b411fc28c91dbb3e7df06cc26b6320/packages/payload/src/database/queryValidation/validateQueryPaths.ts#L69-L73 which potentially can add overhead if you have a large collection/global config UPD: The overhead is even much more than in the benchmark below if you have Lexical with blocks. Benchmark in `relationships/int.spec.ts`: ```ts const now = Date.now() for (let i = 0; i < 10; i++) { const now = Date.now() for (let i = 0; i < 300; i++) { const query = await payload.find({ collection: 'chained', where: { 'relation.relation.name': { equals: 'third', }, and: [ { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, { 'relation.relation.name': { equals: 'third', }, }, ], }, }) } payload.logger.info(`#${i + 1} ${Date.now() - now}`) } payload.logger.info(`Total ${Date.now() - now}`) ``` Before: ``` [02:11:48] INFO: #1 3682 [02:11:50] INFO: #2 2199 [02:11:54] INFO: #3 3483 [02:11:56] INFO: #4 2516 [02:11:59] INFO: #5 2467 [02:12:01] INFO: #6 1987 [02:12:03] INFO: #7 1986 [02:12:05] INFO: #8 2375 [02:12:07] INFO: #9 2040 [02:12:09] INFO: #10 1920 [PASS] Relationships > Querying > Nested Querying > should allow querying two levels deep (24667ms) [02:12:09] INFO: Total 24657 ``` After: ``` [02:12:36] INFO: #1 2113 [02:12:38] INFO: #2 1854 [02:12:40] INFO: #3 1700 [02:12:42] INFO: #4 1797 [02:12:44] INFO: #5 2121 [02:12:46] INFO: #6 1774 [02:12:47] INFO: #7 1670 [02:12:49] INFO: #8 1610 [02:12:50] INFO: #9 1596 [02:12:52] INFO: #10 1576 [PASS] Relationships > Querying > Nested Querying > should allow querying two levels deep (17828ms) [02:12:52] INFO: Total 17818 ```
What?
Improves querying performance of the Local API, reduces copying overhead
How?
Adds
flattenedFieldsproperty for sanitized collection/global config which contains fields in database schema structure.For example, It removes rows / collapsible / unnamed tabs and merges them to the parent
fields, ignores UI fields, named tabs are added astype: 'tab'.This simplifies code in places like Drizzle
transform/traverseFields. Also, now we can avoid callingflattenTopLevelFieldswhich adds some overhead and usecollection.flattenedFields/field.flattenedFields.By refactoring
configToJSONSchema.tswithflattenedFieldsit alsoselectRemoves this deep copying for each
wherequery constraintpayload/packages/payload/src/database/queryValidation/validateQueryPaths.ts
Lines 69 to 73 in 58ac784
UPD:
The overhead is even much more than in the benchmark below if you have Lexical with blocks.
Benchmark in
relationships/int.spec.ts:Before:
After: