-
Notifications
You must be signed in to change notification settings - Fork 228
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
COALESCE in array Contains prevents index usage #1152
Comments
/cc @smitpatel @maumar on a case where null semantics degrades performance because an index isn't used. Am just curious whether we're aware of other cases like this in general (which aren't a result of superfluous checks we haven't yet optimized away). |
@skynet2 just to be sure, can you please post the full LINQ query? I'm specifically interested in whether your array is a constant (specified inline in the query, not as an external variable) and whether id is nullable. FYI the COALESCE is necessary in order to preserve the correct behavior in the face of nulls - but I'll think about what we can do if this has a significant perf impact. |
Hi @roji
Thanks, |
I am not able to understand the difference here. Both of the SQL relates to different tables and selecting different data. What is the expected SQL vs generated SQL? It may be slightly related to the fact that null semantics are not taken care for custom expression. |
Yeah, the LINQ and SQL queries above don't seem to correspond to the SQL. @skynet2, in general, what we need are clear, minimal code samples which show issues, anything else is confusing and creates more work for us. However, it's not surprising that adding the COALESCE causes PG to stop using the index on id: DROP TABLE IF EXISTS data;
CREATE TABLE data (id INT PRIMARY KEY);
INSERT INTO data (id) VALUES (1), (2), (3);
EXPLAIN SELECT * FROM data WHERE id = ANY('{1, 100, 1000}');
EXPLAIN SELECT * FROM data WHERE COALESCE(id = ANY('{1, 100, 1000}')); The version without the COALESCE:
The version with the COALESCE:
FWIW this is exactly the thing that made me open dotnet/efcore#17598 (this case is documented there); once we have a more flexible parameter sniffing architecture, we could look at array parameters at execution time and not generate the COALESCE if there's no null. Until that happens, I think it makes sense to not do null semantics here, i.e. remove the COALESCE for now (nobody really complained before I added it in 3.0). @smitpatel I know this is sacrificing correctness for perf but in this case it may make sense.
That would definitely be a better way of applying the null semantics (and also allowing opt-out when relational nulls are on), but it wouldn't solve the perf issue created by adding the COALESCE... |
Hi @roji @smitpatel , Thanks, |
Because it prevents index usage. Will reimplement after we can sniff the parameter for null values. Fixes #1152
Because it prevents index usage. Will reimplement after we can sniff the parameter for null values. Fixes #1152
I am hitting this. |
In the meantime if anyone hits this you can someArray.ToList() to force an IN translation ICollection<Models.Transactions> invoiceTransactions = _tradingCompanyDbContext.Transactions
.Include(t => t.AccountNoNavigation).ThenInclude(a => a.InvTypeNavigation)
.Include(t => t.AccountNoNavigation).ThenInclude(a => a.PaymentFreqNavigation)
.Include(t => t.InvoiceDetails).ThenInclude(i => i.StockNoNavigation)
.Include(t => t.DiscountDetails)
.Include(t => t.CommentDetails)
.Where(t => invoiceNoStrings.ToList().Contains(t.CustSuppRef)
&& (t.TransCode == 0 || t.TransCode == 1))
.AsNoTracking()
.ToList(); |
@roji we'd be also interested in having this at least in a preview release - or is there anything that breaks by removing coalesce / what are the trade-offs (like as long as you don't use it with a nullable column)? |
@pgrm hang in there, I really intend to release 3.1.1 in the next few days! |
Shoot, seems like I forgot to cherry-pick this to 3.1.1 (just like #1154... not proud here). I will release 3.1.1.2 shortly. Note that this is a small breaking change - anyone relying on the current coalescing behavior may be broken. However, this does seem like the right thing to do until we can bring back proper null semantics for 5.0 (#1142) |
Hello,
Today i updated to the latest version (3.1.0).
After the upgrade, I can see some very strange behavior in queries which leads to a sequence scan instead of index scan as previously.
Details:
Example with 3.1.0
(where $1 = '{1,2,3,4}')
That leads to sequence scan because of coalesce.
Example with 3.0.1
That's is the commit where that change was introduced d7863b8#diff-9091bf8c282a54bfeecb802bb7705561
cc @roji
Thanks,
Stas
The text was updated successfully, but these errors were encountered: