-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Query hints (raw SQL, such as OPTIONs) #6717
Comments
While the idea of integrating arbitrary provider-specific hints in queries seems useful, treating this as some raw SQL to be tacked at the end of the query may be too limited. A specific provider's SQL dialect may require the additional SQL to be integrated somewhere in the middle, etc... Some arbitrary annotations on the query itself which would be picked up by the provider-specific query SQL generator may cover more cases. |
@roji yeah I wasn't intending to limit it to appending text to the end of the query - I removed the word "append" from the title 😄 . |
Ok great :) |
Note from triage: we need to investigate what commonality exists here across relational database systems. For example, where can hints be attached? Is there non-SQL Server value in a query-hint only (i.e. always at the end of the query) solution? /cc @roji @caleblloyd @ErikEJ |
Here's the PostgreSQL documentation page on querying. I'm not sure how many things it has which can be tacked on without impacting the shape of the results (in which case they'd be beyond the scope of this issue). Some ideas that come to mind:
Seems like ideally providers would be able to define an extension method on the IQueryable (like |
* This PR would be a Start for future implementations and improvements in SQL Hints. * Resolve dotnet#11897 * Thought of: dotnet#6717
Design Notes:
Changes to relational level remain pre-requisite for provider level work but the issue remains in backlog for now. Community contributions appreciated. |
cc: @ralmsdeveloper |
Another use case: specifying per-query collation. PostgreSQL allows the following on an expression: SELECT a < b COLLATE "de_DE" FROM test1; or on a clumn: SELECT a COLLATE "de_DE" < b FROM test1; |
@smitpatel agree that the way forward here is by allowing annotations to be specified by the user in the query, and for those annotations to flow to the provider's query SQL generator. The question is indeed granularity and which elements of the query expression tree can be thus annotated. |
Thoughts: We would have to have one more property in TableExpression (public virtual string Hint {get;set;}). Remember that when using the annotation, this would be replicated in the "Include" tables: Or have one more parameter in the extension method: "NoInclude" public static IQueryable<TEntity> With<TEntity>(
this IQueryable<TEntity> source,
string hint,
string optionalParameter = null); Samplevar query = _db
.Blogs
.With("NOLOCK", "INDEX(myIndex)") // Second parameter optional
.ToList(); Output SQLSELECT [p].[Id], [p].[Date], [p].[Name]
FROM [Blogs] AS [p] WITH (NOLOCK, INDEX(myIndex))
--or
SELECT [p].[Id], [p].[Date], [p].[Name]
FROM [Blogs] AS [p] WITH (NOLOCK)
We could also use Enum to do this:This would prevent user typing error. PAGLOCK, NOLOCK, READCOMMITTEDLOCK, ROWLOCK, TABLOCK ou TABLOCKX. Samplevar query = _db
.Blogs
.With(Hints.NOLOCK)
.ToList(); For the @roji example: I believe we can do this in EF.Functions. |
Or just: public static IQueryable<TEntity> Hint<TEntity>(
this IQueryable<TEntity> source,
string hint,
bool repeatForInclude = true); var query = _db
.Blogs
.Hint("WITH (NOLOCK)")
.ToList(); This is left under the responsibility of the user. In my thinking I believe that this also becomes more flexible, the user can theoretically use all available hints, since initially this would be designed only for queries! |
@ralmsdeveloper - That is what we decided explicitly not to do it. Unless there is any common query hint across all providers. Especially we cannot use any method with string parameter where string is going to be appended in SQL, that is just asking for SQL injection. Relational layer will just provide the storage facility in terms of query annotations. So provider methods can add query annotations, (whatever shape), and those annotations will be flowed to SQL generator by relational, where provider can look at annotations and determine what to write in SQL. Further it also avoids breaking TableExpression since there is no need to add anything like |
Any workaround until major updates? I´m using ef 3.1, with some SQL background tasks that frequently update my tables, and I need ef queries to not being locked by that. The database is configured with snapshot. I appreciate any help or tip. Thanks |
@lixaotec Consider using an IDbCommandInterceptor. |
Will give a look @ajcvickers , thank you! |
Is there any chance this is going to make it into EF Core 5 so we will be able to start adding with (nolock) on our queries? |
@wklingler EF Core 5.0 is shipped. The next release will be EF Core 6.0 in November 2021. We are currently going through the planning process for 6.0 and will consider this item. However, keep in mind that there are many other high priority features with which it will be competing for resources. Make sure to add your vote (👍) above. |
That's too bad, thanks for such a quick response! |
Voting for the feature having ran into #23580 For now the only way is to create views on tables with nolock. |
I have not found anything for JOIN hints. It is something I really need: FROM Main
JOIN Another WITH(FORCESEEK) ON Another.ID = Main.ID |
For those who are stuck between a rock and a hard place due to this issue, here is a dirty hack that may work around some cases - for me it did help with 99% of problems and hopefully it can help another lost soul. To use this hack, you will need to replace the default implementation of
Hoping this helps someone. |
@Illya-Clearpoint it shouldn't be necessary to register IQuerySqlGeneratorFactory as transient - normally it's scoped. You can also more easily replace a service with |
@Illya-Clearpoint Database interceptors are often a less risky choice than replacing a service. |
Thanks @roji, in our case we needed to use the application container anyway so it was 6 of one, or half a dozen of the other, but yeah, using |
Thanks @ajcvickers. This hack is by no means a silver bullet for this problem. In our case, I thought to make use of the Interceptors, but could not find a way to make them work at Entity level. In one severe case, we needed to add hints ( For example:
|
Note: table annotations are covered by #6717 - we can use this to track other remaining annotation/metadata. Note that global query hints should already be manageable by extending the QueryCompilationContext (though above we seemed to discuss free-form, text-based hint support where we wouldn't need to add specific support for each hint type - that's slightly different). There's also other hint types (e.g. on joins). |
Note that if we decide to use RECOMPILE when inlining parameterized collections (#34347), we'd need to implement some version of this first. Note that we don't have to do everything: just for our internal use of RECOMPILE we could do something without exposing user-facing APIs for hints. |
Note that query hint support could go in two directions:
We also need to keep in mind the parameterization problem. Query hints (most likely) can't be parameterized in SQL; we can use e.g. |
@roji I need |
An example from #6649 is being able to append
OPTION (MAXRECURSION 2000)
to the end of a query.The text was updated successfully, but these errors were encountered: