I use SQL profiler to know how Entity Framework convert LINQ expression to sql use database. When query is 'heavy' then I try to optimalize it by examine execution plan.
Profiler (I use Profiler Express) give my query in this format
exec sp_executesql N'SELECT
[Project2].[Id] AS [Id], (... rest od query ... )
',#p__linq__0=N'test#mypage.com'
To see execution plan I have to convert (copy, paste code wrrr) to this format
DELARE #p__linq__0 NVARCHAR(100) =N'test#mypage.com'
SELECT
[Project2].[Id] AS [Id], (... rest od query ... )
It is boring ,irritating etc. Does someony know page or somethig which do it for me? Or I can just set it in options?
Enable "Show Actual Execution Plan" and run the query.
Related
Is there any difference between these two LINQ-to-Entities queries:
context.Table.Count(x => ...)
and
context.Table.Where(x => ...).Count()
in terms of performance and generated SQL?
I tried to look generated SQL myself, but I only know how to get the SQL from IQueryable, but Count returns the value directly.
I have managed to see the SQL (thanks to #dasblinkenlight), the answer is - no, both LINQ queries generate exactly the same SQL query, at least for a simple query without a grouping:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Table] AS [Extent1]
WHERE <condition>
) AS [GroupBy1]
I'm trying to make my Linq-to-SQL query more efficient by including child properties in one trip to the DB. I started by trying various linq queries to accomplish this. The queries were getting complex, so I tried the LoadWith() option:
The constructor of my DAL class sets the LoadWith() settings:
public TrackerJobData()
{
dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<TrackerJobRecord>(x => x.SpecBarcodeRecords);
dataLoadOptions.LoadWith<TrackerJobRecord>(x => x.TrackerJobEquipmentTriggerRecords);
dataLoadOptions.LoadWith<TrackerJobRecord>(x => x.EtaRecord);
this.Database.LoadOptions = dataLoadOptions;
}
And here is the query I'm using:
public TrackerJob GetItem(int trackerJobId)
{
TrackerJobRecord record =
(from trackerJob in this.Database.TrackerJobRecords
where trackerJob.TrackerJobId == trackerJobId
select trackerJob).FirstOrDefault();
return record.Map();
}
When I debug and F10 on just the linq query (not the return), I get this output in SQL Profiler:
Pardon my ignorance of SQL Profiler, but do the three highlighted lines mean there were three round trips from the client (my code) to the server? If so, why? Will SQL Server ever execute multiple sp_executesql calls in one trip?
And since I thought LoadWith() would eliminate multiple calls, what am I doing incorrectly?
EDIT
Here are the three statements within SQL Profiler:
exec sp_executesql N'SELECT TOP (1) [t0].[TrackerJobId], [t0].[Name], [t0].[EtaId], [t0].[SamplingProcessorTypeId], [t0].[Description], [t0].[LastModifiedUser], [t0].[LastModifiedTime], [t0].[VersionNumber], [t0].[Active], [t0].[Archived], [t1].[EtaId] AS [EtaId2], [t1].[EtaNumber], [t1].[Title], [t1].[State], [t1].[DateInitialized], [t1].[EtaOriginatorId], [t1].[Quantity], [t1].[Ehs], [t1].[Ship], [t1].[InternalUse], [t1].[DateClosed], [t1].[ExperimentId], [t1].[Disposition], [t1].[TestType], [t1].[LastModifiedUser] AS [LastModifiedUser2], [t1].[LastModifiedTime] AS [LastModifiedTime2], [t1].[VersionNumber] AS [VersionNumber2]
FROM [AutoTracker].[TrackerJob] AS [t0]
INNER JOIN [Global].[Eta] AS [t1] ON [t1].[EtaId] = [t0].[EtaId]
WHERE [t0].[TrackerJobId] = #p0',N'#p0 int',#p0=17
exec sp_executesql N'SELECT [t0].[SpecBarcodeId], [t0].[TrackerJobId], [t0].[EquipmentId], [t0].[StartTime], [t0].[EndTime], [t0].[LastModifiedUser], [t0].[LastModifiedTime], [t0].[VersionNumber]
FROM [AutoTracker].[SpecBarcode] AS [t0]
WHERE [t0].[TrackerJobId] = #x1',N'#x1 int',#x1=17
exec sp_executesql N'SELECT [t0].[TrackerJobId], [t0].[EquipmentId], [t0].[LastModifiedUser], [t0].[LastModifiedTime], [t0].[VersionNumber]
FROM [AutoTracker].[TrackerJobEquipmentTrigger] AS [t0]
WHERE [t0].[TrackerJobId] = #x1',N'#x1 int',#x1=17
Linq-2-sql LoadWith does not support multiple 1:N relationships.
http://weblogs.asp.net/zeeshanhirani/archive/2008/08/11/constraints-with-loadwith-when-loading-multiple-1-n-relationships.aspx
Linq2SQl eager load with multiple DataLoadOptions
Each of those SQL Profiler calls represents a single roundtrip from client to DB server instance. SQL Server does support returning data sets in a single roundtrip, but I'm not sure how you would do that with LINQ to SQL.
I have a following query in nHibernate. The idea is to get first and last measurement time of certain data group.
var measurements = _session.Query<Measurement>()
.Where(x => categories.Contains(x.CategoryId));
first = measurements.Min(o => o.StartTime);
last = measurements.Max(o => o.StartTime);
The SQL Server Profiler gives following output:
exec sp_executesql N'select cast(min(measuremen0_.StartTime) as DATETIME) as col_0_0_ from Measurement measuremen0_ where measuremen0_.Category in (#p0 , #p1)',N'#p0 int,#p1 int',#p0=7654321,#p1=3324673
exec sp_executesql N'select cast(max(measuremen0_.StartTime) as DATETIME) as col_0_0_ from Measurement measuremen0_ where measuremen0_.Category in (#p0 , #p1)',N'#p0 int,#p1 int',#p0=7654321,#p1=3324673
Can I somehow optimize this without using HQL, so that it would create only one request to the database server?
Did you take a look at the Future Queries? I think it works for linq queries as well.
I have a query linq like this:
var query = from c in Context.Customers select c;
var result = query.ToList();
Linq query generate this tsql code:
exec sp_executesql N'SELECT
[Project1].[Id] AS [Id],
[Project1].[Name] AS [Name],
[Project1].[Email] AS [Email]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent1].[Email] AS [Email]
FROM [dbo].[Customers] AS [Extent1] ) AS [Project1]
Is there a way for not generate subquery?
Do you have any evidence that that query is causing performance problems? I imagine the query-optimizer would easily recognize that.
If you're certain after profiling that the query is a performance problem (doubtful) - and only then - you could simply turn the query into a stored procedure, and call that instead.
You use a tool like Linq because you don't want to write SQL, before abandoning that you should at least compare the query plan of your proposed SQL vs that generated by the tool. I don't have access to SQL Studio at the moment, but I would be a bit surprised if the query plans aren't identical...
EDIT: having had a chance to check out the query plans, they are in fact identical.
Short answer: No you cannot modify that query.
Long answer: If you want to reimplement Linq provider and query generator then perhaps there is a way but I doubt you want to do that. You can also implement custom EF provider wrapper which will take query passed from EF and reformat it but that will be hard as well - and slow. Are you going to write custom interpreter for SQL queries?
I'm trying to figure out if there's a way to retrieve the (full) sql statement that gets executed on the database server.
I found something already, but it does not exactly what I would like:
IQueryable<SomeType> someQuery = ...
string command = dataContext.GetCommand(query).CommandText;
In my case this gives me a command string something like:
SELECT TOP (50) [t0].[ID], ....
FROM [dbo].[someTable] AS [t0]
WHERE ([t0].[someColumn] IS NOT NULL) AND (([t0].[someColumn]) IN (#p0))
On database there's executed:
exec sp_executesql N'SELECT TOP (50) [t0].[ID], ...
FROM [dbo].[someTable] AS [t0]
WHERE ([t0].[someColumn] IS NOT NULL) AND (([t0].[someColumn]) IN (#p0, #p1))',N'#p0 int,#p1 int',#p0=401,#p1=201
Is there a way to retrieve this 'full' statement (so also the parameter values) from C# code?
You can also see the generated sql query if you have an instance of
IQueryable<T> and call the .ToString() method.
For Example:
var db = new DbContext();
IQueryable<Blog> query = db.Blog.Where(tt=> tt.Id > 100).OrderByDescending(tt=>tt.Id);
var sqlString = query.ToString();
Console.WriteLine(sqlString);
This will generate an output of:
SELECT [Extent1].[Id] AS [Id],
[Extent1].[Title] AS [Title],
[Extent1].[Author] AS [Author],
[Extent1].[Text] AS [Text],
[Extent1].[CreatedAt] AS [CreatedAt],
[Extent1].[UpdatedAt] AS [UpdatedAt]
FROM [dbo].[Blogs] AS [Extent1]
WHERE [Extent1].[Id] > 100
ORDER BY [Extent1].[Id] DESC
Once you get the Command you can print the CommandText and then loop through the Parameters collection and print all the individual parameters.
Also there is the linq-to-sql debug visualizer which does the same in debug mode.
A really nice tool to view the queries as they are happening is the Linq-to-sql profiler
In the latest version of EF Core 5 ToQueryString,
query.ToQueryString()
(SqlCommand)dataContext.GetCommand(query)
will give you access to Parameters collection.
I'm using Datacontext.Log property to get the generated SQL Statement (it includes the statement text, and parameters).
Just set YourDataContext.Log = SomeTextWriter.
It can be written to a file (Log = new StreamWriter(#"c:\temp\linq.log")) or to debug window, see this post
When viewing the IQueryable in the Locals pane, you can access DebugView > Query, which will contain the SQL statement.