-
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
Consider ensuring that split query ordering is deterministic, either warning/throwing if not or injecting the primary key properties #34722
Comments
Note that just having an ordering isn't sufficient - the ordering has to be fully deterministic. The above query contains: OrderByDescending(x => x.Baskets.AsQueryable().Where(GetPredicate()).Sum(x => x.Quantity * x.SalePrice)) So two rows could happen to have the same Quantity*SalePrice value, at which point the ordering is undefined and can vary. Try adding ThenBy() with the ID - that should make the ordering fully deterministic. Beyond that, is the row dropping occuring while concurrent updates are happening to the table? If so, then that's probably expected - you may need to use a higher transaction isolation level to ensure consistent results across the split queries. Otherwise, if you can reproduce this without any concurrent updates, then I'll need a minimal, runnable repro in order to investigate further. |
Damn, I should have known there'd be more to it
Adding the Is this something that could be introduced easily? If so, is there a good place you can point me to? Maybe I can help, as I already having a little experience with expression-building (plug package again!! 😂) SQL ChangesDiff comparison: SQL - Diffchecker.pdf /*
* First Part (RETURNS 51 LINES)
*/
--Microsoft.EntityFrameworkCore.Database.Command: Information: Executed DbCommand (305ms) [Parameters=[@__p_0='0', @__p_1='51'], CommandType='Text', CommandTimeout='30']
DECLARE @__p_0 INT ='0', @__p_1 INT ='51'; -- NOTE: Equivalent to the line above
SELECT [p].[pName], [p].[pInStock], CAST([p].[pInStock] AS float) * [p].[pPrice], [p].[pID]
FROM [products] AS [p]
WHERE EXISTS (
SELECT 1
FROM [cart] AS [c]
LEFT JOIN [orders] AS [o] ON [c].[cartOrderID] = [o].[ordID]
WHERE [p].[pID] = [c].[cartProdID] AND [c].[cartQuantity] > 0 AND ([c].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c].[cartMerchID]))) = N'' OR [c].[cartMerchID] = N'\\\TERM///') AND [o].[ordID] IS NOT NULL AND [o].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o].[ordID] IS NOT NULL AND CONVERT(date, [o].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o].[ordDate]) <= '2023-09-17T00:00:00.000')
ORDER BY (
SELECT COALESCE(SUM(CAST([c0].[cartQuantity] AS float) * [c0].[cartProdPrice]), 0.0E0)
FROM [cart] AS [c0]
LEFT JOIN [orders] AS [o0] ON [c0].[cartOrderID] = [o0].[ordID]
WHERE [p].[pID] = [c0].[cartProdID] AND [c0].[cartQuantity] > 0 AND ([c0].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c0].[cartMerchID]))) = N'' OR [c0].[cartMerchID] = N'\\\TERM///') AND [o0].[ordID] IS NOT NULL AND [o0].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c0].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o0].[ordID] IS NOT NULL AND CONVERT(date, [o0].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o0].[ordDate]) <= '2023-09-17T00:00:00.000') DESC, [p].[pID]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY
/*info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (305ms) [Parameters=[@__p_0='0', @__p_1='51'], CommandType='Text', CommandTimeout='30']
SELECT [p].[pName], [p].[pInStock], CAST([p].[pInStock] AS float) * [p].[pPrice], [p].[pID]
FROM [products] AS [p]
WHERE EXISTS (
SELECT 1
FROM [cart] AS [c]
LEFT JOIN [orders] AS [o] ON [c].[cartOrderID] = [o].[ordID]
WHERE [p].[pID] = [c].[cartProdID] AND [c].[cartQuantity] > 0 AND ([c].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c].[cartMerchID]))) = N'' OR [c].[cartMerchID] = N'\\\TERM///') AND [o].[ordID] IS NOT NULL AND [o].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o].[ordID] IS NOT NULL AND CONVERT(date, [o].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o].[ordDate]) <= '2023-09-17T00:00:00.000')
ORDER BY (
SELECT COALESCE(SUM(CAST([c0].[cartQuantity] AS float) * [c0].[cartProdPrice]), 0.0E0)
FROM [cart] AS [c0]
LEFT JOIN [orders] AS [o0] ON [c0].[cartOrderID] = [o0].[ordID]
WHERE [p].[pID] = [c0].[cartProdID] AND [c0].[cartQuantity] > 0 AND ([c0].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c0].[cartMerchID]))) = N'' OR [c0].[cartMerchID] = N'\\\TERM///') AND [o0].[ordID] IS NOT NULL AND [o0].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c0].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o0].[ordID] IS NOT NULL AND CONVERT(date, [o0].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o0].[ordDate]) <= '2023-09-17T00:00:00.000') DESC, [p].[pID]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY*/
/*
* Second Part (RETURNS 99 LINES)
*/
-- Microsoft.EntityFrameworkCore.Database.Command: Information: Executed DbCommand (582ms) [Parameters=[@__p_0='0', @__p_1='51'], CommandType='Text', CommandTimeout='30']
-- NOTE: @__p_0, @__p_1 are the same so I don't re-set them
SELECT [t0].[cartQuantity], [t0].[cartProdPrice], [t].[pID]
FROM (
SELECT [p].[pID], (
SELECT COALESCE(SUM(CAST([c0].[cartQuantity] AS float) * [c0].[cartProdPrice]), 0.0E0)
FROM [cart] AS [c0]
LEFT JOIN [orders] AS [o0] ON [c0].[cartOrderID] = [o0].[ordID]
WHERE [p].[pID] = [c0].[cartProdID] AND [c0].[cartQuantity] > 0 AND ([c0].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c0].[cartMerchID]))) = N'' OR [c0].[cartMerchID] = N'\\\TERM///') AND [o0].[ordID] IS NOT NULL AND [o0].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c0].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o0].[ordID] IS NOT NULL AND CONVERT(date, [o0].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o0].[ordDate]) <= '2023-09-17T00:00:00.000') AS [c]
FROM [products] AS [p]
WHERE EXISTS (
SELECT 1
FROM [cart] AS [c]
LEFT JOIN [orders] AS [o] ON [c].[cartOrderID] = [o].[ordID]
WHERE [p].[pID] = [c].[cartProdID] AND [c].[cartQuantity] > 0 AND ([c].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c].[cartMerchID]))) = N'' OR [c].[cartMerchID] = N'\\\TERM///') AND [o].[ordID] IS NOT NULL AND [o].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o].[ordID] IS NOT NULL AND CONVERT(date, [o].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o].[ordDate]) <= '2023-09-17T00:00:00.000')
ORDER BY (
SELECT COALESCE(SUM(CAST([c0].[cartQuantity] AS float) * [c0].[cartProdPrice]), 0.0E0)
FROM [cart] AS [c0]
LEFT JOIN [orders] AS [o0] ON [c0].[cartOrderID] = [o0].[ordID]
WHERE [p].[pID] = [c0].[cartProdID] AND [c0].[cartQuantity] > 0 AND ([c0].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c0].[cartMerchID]))) = N'' OR [c0].[cartMerchID] = N'\\\TERM///') AND [o0].[ordID] IS NOT NULL AND [o0].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c0].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o0].[ordID] IS NOT NULL AND CONVERT(date, [o0].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o0].[ordDate]) <= '2023-09-17T00:00:00.000') DESC, [p].[pID]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY
) AS [t]
INNER JOIN (
SELECT [c1].[cartQuantity], [c1].[cartProdPrice], [c1].[cartProdID]
FROM [cart] AS [c1]
LEFT JOIN [orders] AS [o1] ON [c1].[cartOrderID] = [o1].[ordID]
WHERE [c1].[cartQuantity] > 0 AND ([c1].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c1].[cartMerchID]))) = N'' OR [c1].[cartMerchID] = N'\\\TERM///') AND [o1].[ordID] IS NOT NULL AND [o1].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c1].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o1].[ordID] IS NOT NULL AND CONVERT(date, [o1].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o1].[ordDate]) <= '2023-09-17T00:00:00.000'
) AS [t0] ON [t].[pID] = [t0].[cartProdID]
ORDER BY [t].[c] DESC, [t].[pID]
/*info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (582ms) [Parameters=[@__p_0='0', @__p_1='51'], CommandType='Text', CommandTimeout='30']
SELECT [t0].[cartQuantity], [t0].[cartProdPrice], [t].[pID]
FROM (
SELECT [p].[pID], (
SELECT COALESCE(SUM(CAST([c0].[cartQuantity] AS float) * [c0].[cartProdPrice]), 0.0E0)
FROM [cart] AS [c0]
LEFT JOIN [orders] AS [o0] ON [c0].[cartOrderID] = [o0].[ordID]
WHERE [p].[pID] = [c0].[cartProdID] AND [c0].[cartQuantity] > 0 AND ([c0].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c0].[cartMerchID]))) = N'' OR [c0].[cartMerchID] = N'\\\TERM///') AND [o0].[ordID] IS NOT NULL AND [o0].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c0].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o0].[ordID] IS NOT NULL AND CONVERT(date, [o0].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o0].[ordDate]) <= '2023-09-17T00:00:00.000') AS [c]
FROM [products] AS [p]
WHERE EXISTS (
SELECT 1
FROM [cart] AS [c]
LEFT JOIN [orders] AS [o] ON [c].[cartOrderID] = [o].[ordID]
WHERE [p].[pID] = [c].[cartProdID] AND [c].[cartQuantity] > 0 AND ([c].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c].[cartMerchID]))) = N'' OR [c].[cartMerchID] = N'\\\TERM///') AND [o].[ordID] IS NOT NULL AND [o].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o].[ordID] IS NOT NULL AND CONVERT(date, [o].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o].[ordDate]) <= '2023-09-17T00:00:00.000')
ORDER BY (
SELECT COALESCE(SUM(CAST([c0].[cartQuantity] AS float) * [c0].[cartProdPrice]), 0.0E0)
FROM [cart] AS [c0]
LEFT JOIN [orders] AS [o0] ON [c0].[cartOrderID] = [o0].[ordID]
WHERE [p].[pID] = [c0].[cartProdID] AND [c0].[cartQuantity] > 0 AND ([c0].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c0].[cartMerchID]))) = N'' OR [c0].[cartMerchID] = N'\\\TERM///') AND [o0].[ordID] IS NOT NULL AND [o0].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c0].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o0].[ordID] IS NOT NULL AND CONVERT(date, [o0].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o0].[ordDate]) <= '2023-09-17T00:00:00.000') DESC, [p].[pID]
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY
) AS [t]
INNER JOIN (
SELECT [c1].[cartQuantity], [c1].[cartProdPrice], [c1].[cartProdID]
FROM [cart] AS [c1]
LEFT JOIN [orders] AS [o1] ON [c1].[cartOrderID] = [o1].[ordID]
WHERE [c1].[cartQuantity] > 0 AND ([c1].[cartMerchID] IS NULL OR LOWER(LTRIM(RTRIM([c1].[cartMerchID]))) = N'' OR [c1].[cartMerchID] = N'\\\TERM///') AND [o1].[ordID] IS NOT NULL AND [o1].[ordStatus] > CAST(2 AS smallint) AND LOWER(LTRIM(RTRIM([c1].[cartProdName]))) LIKE N'%\\\TERM///%' AND 1 = 1 AND [o1].[ordID] IS NOT NULL AND CONVERT(date, [o1].[ordDate]) >= '2023-09-01T00:00:00.000' AND CONVERT(date, [o1].[ordDate]) <= '2023-09-17T00:00:00.000'
) AS [t0] ON [t].[pID] = [t0].[cartProdID]
ORDER BY [t].[c] DESC, [t].[pID]*/ |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as off-topic.
Is this not the same as #26808? |
Duplicate of #26808 |
Good catch @ascott18, thanks... Closing as duplicate. |
Edit
Comment #34722 (comment) better reflects the updated subject of this issue. The original report is detailed below (for reference)
Original Issue Report
As far as I'm aware, I've not done anything wrong. This isn't the end of the world either, as I've stopped using
QuerySplittingBehavior.SplitQuery
while building the options. As I know splitting isn't default, this won't be high on the scale of fixes - just wanted to raise it.File a bug
I have a query that has
.Skip(..)
,.Take(..)
and.OrderBy(..)
(definitely has the ordering, before you ask 😁). If I split the query, globally or with.AsSplitQuery()
, some results are dropped leaving a sub-collection in the record empty. I know they're being dropped because the missing lines are there if I run the generated query directly against the DB.Include your code
Here's a simplified piece of code for the query I'm running. The
GetPredicate()
call builds and stores a built predicate for repeat calls - just in case it's important/relevant, I make the predicate/expression usingTopMarksDevelopment.ExpressionBuilder
(nuget, github - only a mild self-plug 😂)Include stack traces
N/A. It's not an exception that's thrown, just missing results
Include verbose output
First, sorry it's a mess
I took the console output, commented out irrelevant areas and added the declarations so it could be run in SQL SMS (if required)
I also wanted to mention; the second part of the split query returns 99 lines and the single query also returns 99 lines - so there's no disparity there
Split Query
Single Query
Include provider and version information
EF Core version: 8.0.8
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 8.0
Operating system: Windows 11 && Windows Server 2019
IDE: VS Code
I hope this is all helpful and if you need anything else, let me know
The text was updated successfully, but these errors were encountered: