Sample Header Ad - 728x90

Performance issues in parameterized queries accessing a view in SQL Server

9 votes
3 answers
1948 views
I am currently facing an issue with parameterized queries in SQL Server that I do not understand where it is rooted in. I broke it down to a simple example: Let's assume a table that holds data about some child entity as well as the parent_id and a corresponding index on the parent_id. The data is accessed based on this parent_id but through a view that, additionally to the table data, holds a column calculating a row_number over all entries partitioned by the parent_id. ### Reproducable setup Create the table, index and view as follows:
CREATE TABLE dbo.test (id BIGINT IDENTITY(1,1), text NVARCHAR(255), parent_id BIGINT);
GO

CREATE NONCLUSTERED INDEX idx_test_parent_id
       ON dbo.test (parent_id);
GO

CREATE VIEW dbo.test_view
AS
  SELECT *, ROW_NUMBER() OVER (PARTITION BY parent_id ORDER BY id) AS row_num
  FROM dbo.test
GO
Now get some data into the table:
DECLARE @i BIGINT = 0
WHILE @i < 200000
BEGIN
    SET @i = @i + 1
    INSERT INTO dbo.test (text, parent_id)
    VALUES ('test 1', @i), ('test 2', @i), ('test 3', @i);
END
### The issue When accessing the data through a parameterized query from the view the SQL Server will do a full scan on the table.
DECLARE @parent_id BIGINT = 123456
SELECT *
FROM dbo.test_view
WHERE parent_id = @parent_id
query plan full table scan While when accessing the data directly (without using a parameter) we will get the expected index seek.
SELECT *
FROM dbo.test_view
WHERE parent_id = 123456
query plan index seek ### What I have tried Searching different forums, I do not really understand what is happening here. I have found similar issues where the parameter had the wrong data type and thus performance was bad, but this is not an issue in my case. I also read about issues with parameter sniffing but I neither think this is a problem here as I do not access data through stored procedures or functions. Also, when I am accessing the data directly from the table with a parameterized query the issue will not occur. An index seek is done even with the parameters. Same happens when I add the OPTION (RECOMPILE) to the query accessing the view with a parameterized query the SQL Server will end up doing an index seek. ### Question Can someone explain what the issue is here? How come that this is an issue for the view but not for the table itself? Do I really need to get rid of the view calculating this row_number differently during inserts/deletes? ### Setup - SQL Server 2022 v16.0.4165 running in a docker container - Docker image: mcr.microsoft.com/mssql/server:2022-latest The real table has a primary key of course. But it also has a lot more columns then only the text column. Including all of these columns in the index would be a possibility. The issue though is not occurring when selecting from the table itself, so it seems not to be an issue of the index to me. I was not aware that I am running the database in a compatibility mode. In the productive environment I am even getting CardinalityEstimationModelVersion="140". I do not think that I have set it up anywhere on purpose. ### Execution plans - direct select with index seek - parameterized select with full table scan - Full table scan with QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_150
Asked by jkohl (93 rep)
Feb 5, 2025, 12:11 PM
Last activity: Feb 6, 2025, 12:24 PM