Skip to content

Avoid re-using query plan embedding different constant values. #1542

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

fredericDelaporte
Copy link
Member

@fredericDelaporte fredericDelaporte commented Jan 19, 2018

As said in #1363, I find the insideSelectClause trick a bit hackish, and I was willing to investigate patches from #1363 and #866 corresponding JIRAs.
The one from #1363 was quite interesting, but is missing cases where the constant is not parameterized while not being in select clause (handled by a post transformer), as in #866. (Cases which are also missed by the insideSelectClause trick.)
Patch from #866 just addresses custom LINQ extensions needing to signal a constant as non-parameterized. So it was fixing just a very small subset of the trouble, while requiring many changes, both in NHibernate and on user side.

Here I propose yet another way: detect than some constants have not been used as parameters, and refine adequately the plan caching. This must be a two steps process since such constants are only known once the plan has been generated.
So at that point, if such constants are detected, the query is flagged as refined, it has a new refined key, and it is cached for that additional key, along with being cached with its "original" key.
On cache hit with a non-refined key, the key is refined thanks to plan's query informations, and checked against plan's query again. If not matching, it is looked-up again, but this time with the key already refined.

It allows to remove the insideSelectClause trick, and solves most of the cases. Only the "cached object instance" issue remains, but with a workaround.

If this PR is merged before #1540, #1540 would then be obsoleted and no more needed.

 * Fixes nhibernate#1330 (NH-3673)
 * Obsoletes nhibernate#866 (NH-2658)
 * Fixes most of nhibernate#1363 (a workaround is still needed for one case; NH-2500)
plan = new QueryExpressionPlan(queryExpression, shallow, enabledFilters, factory);
planCache.Put(key, plan);

if (wasAlreadyRefined == false && refinableQuery.RefinedKey)
Copy link
Member Author

@fredericDelaporte fredericDelaporte Jan 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, instead of caching with original and refined key, we could take quite a different path: cache nothing. So the RefinedKey would be renamed NotCacheable, it would be checked right after plan generation, and if true, the plan would not be put in cache. It would have several benefits:

In #1363, some users were even asking for a way to fully disable the query plan cache, writing they were not feeling a performance hit for not having it. Here it would disable it only for queries embedding constants which are not translated to HQL parameters, so it will be even less likely to have a negative impact.

Update: now proposed in #1544.

@fredericDelaporte
Copy link
Member Author

Replaced by #1544.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NH-3673 - Closure variable values locked in from expressions in NHibernate LINQ provider
1 participant