Skip to content

Improve replacePropertyNames performance#4760

Merged
imnotjames merged 3 commits intotypeorm:masterfrom
mohd-akram:improve-query-perf
Oct 8, 2020
Merged

Improve replacePropertyNames performance#4760
imnotjames merged 3 commits intotypeorm:masterfrom
mohd-akram:improve-query-perf

Conversation

@mohd-akram
Copy link
Copy Markdown
Contributor

I did some profiling and found that this function was a bottleneck when using a cache. With these changes I was able to get about 5x better performance.

@mohd-akram
Copy link
Copy Markdown
Contributor Author

@pleerock Could this be merged?

@pleerock
Copy link
Copy Markdown
Member

@Kononnable @vlapo can you guys help to review this one?

@mohd-akram
Copy link
Copy Markdown
Contributor Author

This seems more useful now given #5309.

@thynson
Copy link
Copy Markdown

thynson commented May 15, 2020

I also run into these code when profiling. @mohd-akram's work looks good.

@henrinormak
Copy link
Copy Markdown

Any update on this? Anything blocking this improvement?

@joras
Copy link
Copy Markdown
Contributor

joras commented Aug 12, 2020

This function is most prominent one in the profiling results of our services, and I guess it applies for other DB heavy code. Any speedup to this would be with significant effect.

@elmarti
Copy link
Copy Markdown

elmarti commented Aug 21, 2020

As mentioned this is proving to be a significant bottleneck given #5309

@imnotjames
Copy link
Copy Markdown
Contributor

Are there tests that verify this? There's none here, but I'm guessing there's tests that verify the functionality otherwise.

Comment thread src/query-builder/QueryBuilder.ts
@imnotjames
Copy link
Copy Markdown
Contributor

Rebased against master. Gonna go looking to make sure we've got tests.

@imnotjames
Copy link
Copy Markdown
Contributor

Oracle fails with this - doesn't in master and it's not the changes I added. Looking..

@imnotjames
Copy link
Copy Markdown
Contributor

imnotjames commented Oct 8, 2020

Oh.. oh wow.

This passes before & fails now because NOW we're correctly escaping regular expressions.... but before we weren't. So a . was getting included in the pattern inadvertently & allowing issue 215's test to pass.

The failure in question:

p.author_id = n.id is the item we're escaping. When we escape this value, we go through every column, including relations.

There's a relation to an Author here at the property author - from author_id to author.id. This got included in the regex as author.id because it's the property path - author and then id within author. It should have escaped it, but it didn't, so it was matching author_id. This means if you didn't follow that pattern you'd break it. EG,

    @OneToOne(type => Author)
    @JoinColumn({name: "foo"})
    author: Author;

// Later, calling on a query builder
   .leftJoinAndMapOne("p.author", Author, "n", "p.foo = n.id")

This means that we generated invalid identifiers for oracle.

Adding the replacement:

                if (!(column.databaseName in replacements))
                    replacements[column.databaseName] = column.databaseName;

fixes it!

@imnotjames
Copy link
Copy Markdown
Contributor

Bonus win - this fixes some undesired and undefined behavior! Wonderful.

the `databaseName` prop on the alias isn't recognized for replacement
so this adds it
@imnotjames imnotjames merged commit d86671c into typeorm:master Oct 8, 2020
@imnotjames
Copy link
Copy Markdown
Contributor

Thanks for the contribution!

@mohd-akram mohd-akram deleted the improve-query-perf branch October 8, 2020 06:30
@ldiqual
Copy link
Copy Markdown

ldiqual commented Oct 20, 2020

@imnotjames Any chance you could push this in a new release? This should be a huge improvement and I couldn't find a way to install the master branch in my project directly (unless there's a way to do that?) Thank you so much

@pleerock
Copy link
Copy Markdown
Member

a new release will be available this week

@MorelSerge
Copy link
Copy Markdown

MorelSerge commented Nov 6, 2020

This breaks QueryBuilder from 0.2.29 on React Native due to lack of support for positive lookbehinds.

Edit: The error is:

Invalid regular expression: invalid group specifier name

Edit2: Relevant:

@mohd-akram
Copy link
Copy Markdown
Contributor Author

The lookbehind could be removed by adjusting the replacement function (see the first commit for inspiration).

@chriswep
Copy link
Copy Markdown
Contributor

@imnotjames @pleerock this broke typeorm on iOS webkit (which doesn't support lookbehind, not even in iOS 14).

unfortunately all of the last typeorm releases where instantly failing on my app project (via Ionic). Even if a node-environment is the most common use of typeorm, I'd think that hybrid apps are still a significant use case. i think there needs to be some way to catch at least those basic issues before merging PRs.

@sandro-salles
Copy link
Copy Markdown

@mohd-akram @pleerock @imnotjames is it possible to revert or add a new version of this change without the lookbehind so it can work on React native again? I'd love to help... but the regex is a little bit too complex for my knowledge... :/

zaro pushed a commit to zaro/typeorm that referenced this pull request Jan 12, 2021
Reduce the number of regular expressions created & strings created when replacing the property names in a statement.
pleerock added a commit that referenced this pull request Jan 12, 2021
@pleerock
Copy link
Copy Markdown
Member

Reverted by #7269 . Fix will be available in 0.2.31.

@elsasslegend
Copy link
Copy Markdown

But what about the initial fix about replacePropertyNames performance ? Isn't it merged in anymore ?

draaglom added a commit to draaglom/typeorm that referenced this pull request May 1, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in typeorm#4760,
There are still outstanding issues relating to perf e.g. typeorm#3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
draaglom added a commit to draaglom/typeorm that referenced this pull request May 1, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in typeorm#4760,
There are still outstanding issues relating to perf e.g. typeorm#3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
draaglom added a commit to draaglom/typeorm that referenced this pull request May 1, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in typeorm#4760,
There are still outstanding issues relating to perf e.g. typeorm#3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
draaglom added a commit to draaglom/typeorm that referenced this pull request May 1, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in typeorm#4760,
There are still outstanding issues relating to perf e.g. typeorm#3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
AlexMesser pushed a commit that referenced this pull request May 20, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in #4760,
There are still outstanding issues relating to perf e.g. #3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
frangz pushed a commit to loyaltylion/typeorm that referenced this pull request Nov 14, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in typeorm#4760,
There are still outstanding issues relating to perf e.g. typeorm#3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
frangz pushed a commit to loyaltylion/typeorm that referenced this pull request Nov 14, 2022
Motivation: the query builder (and within it, replacePropertyNames and
associated functions) is pretty CPU intensive. For our workload, it's
one of the hottest functions in our entire stack.

While improved in typeorm#4760,
There are still outstanding issues relating to perf e.g. typeorm#3857

As we all know though, the first step in optimization is to measure
systematically ;)

https://wiki.c2.com/?ProfileBeforeOptimizing

On my machine, this benchmark runs in ~3500ms or about 0.35ms/query.
This tells us there's a way to go - on my stack, that's about 1/3 of a
typical query's latency!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.