I am running SQL Server 2019 RTM CU18 I am in the process of testing workloads against this server before migrating to it. All databases are set to SQL 2019 compatibility level.
I am finding that using the database scoped config legacy_cardinality_estimation = on seems to make a lot of queries run faster.
Anyway, I have noticed something strange. I have enabled legacy_cardinality_estimation but there is a particular query that most of the the time still uses CardinalityEstimationModelVersion 150 instead of 70 like it's supposed to.
Sometimes it will run with CardinalityEstimationModelVersion 70 and other times 150.
Why is this? Under which conditions would the same query choose to use CardinalityEstimationModelVersion 150 even though the DB has been specifically set with legacy_cardinality_estimation = on.
The query is part of a stored procedure that is built dynamically. Also, there is a recompile hint on the query.
Any ideas?
Thanks
Further Investigations:
I have turned off legacy cardinality estimation and changed the database to compatibility level 110. The same thing happens With certain executions of this query, it runs with 150 CE
What I have noticed is that when it chooses to run with 150 CE - This is when no rows are returned by the query
The first 2 rows are executions with 150 CE
The bottom 2 rows are executions with Legacy CE
Also, with the 150 CE executions - There is an Implicit Conversion warning in the plan
Not sure if all these things are clues to what is going on here.
More Investigations:
DatabaseContextSettingsId="8" ParentObjectId="0" StatementParameterizationType="1" RetrievedFromCache="false" StatementSubTreeCost="14.2801" StatementEstRows="2777.06" SecurityPolicyApplied="false" StatementOptmLevel="FULL" QueryHash="0x7E6FC3AE7781DFB0" QueryPlanHash="0x5528C4469CB66921" CardinalityEstimationModelVersion="70">
DatabaseContextSettingsId="8" ParentObjectId="0" StatementParameterizationType="1" RetrievedFromCache="false" StatementSubTreeCost="0.0295867" StatementEstRows="1" SecurityPolicyApplied="false" StatementOptmLevel="FULL" QueryHash="0x7E6FC3AE7781DFB0" QueryPlanHash="0xAA261B593A12FBD4" StatementOptmEarlyAbortReason="GoodEnoughPlanFound" CardinalityEstimationModelVersion="150">
At this point, I am just trying to understand why or under which conditions the optimizer would change the CE model.
Furthermore:
The statement joins onto several views all of which reference DB's that are set with legacy cardinality estimation = on
There is a cross apply to an Inline TVF the contents of which also reference DB's with legacy cardinality estimation = on